Introduction

In 2017, the Tuveson Lab at Cold Spring Harbor Cancer Center published a paper written by Elyada et al (2017) that detailed the discovery of cancer-associated fibroblasts (CAFs) in mice. The subtypes were then validated in human samples affected with PDAC in a subsequent paper released in 2019. Here we will use SCISSORS to identify the CAF subtypes within the larger fibroblast population, immune cell types within broadly-defined immune clusters, and ductal & PDAC subtypes within the ductal group.

Libraries

R

library(pals)        # high N discrete color palettes
library(VAM)         # single cell GSEA
library(dplyr)       # tidy data 
library(Seurat)      # single cell infrastructure
library(ggplot2)     # plots
library(SingleR)     # cell type assignment
library(decoderr)    # de novo deconvolution 
library(SCISSORS)    # our package
library(mixtools)    # Gaussian mixture model estimation
library(patchwork)   # plot grids
library(paletteer)   # more color palettes
library(CONICSmat)   # CNV estimation
library(reticulate)  # Python interface
library(wesanderson) # even more color palettes

Python

import numpy as np
from openTSNE import TSNEEmbedding
from openTSNE import initialization
from openTSNE.affinity import Multiscale
from openTSNE.affinity import PerplexityBasedNN

Data

First we load in the \(\text{gene} \times \text{cell}\) counts matrix, then create a Seurat object to hold it in. Next, we add samplename, tissue type, and patient sex metadata taken from the publicly available dataset.

raw_counts <- Read10X(data.dir = "~/Desktop/Data/Elyada Raw/All Human/")
pdac <- CreateSeuratObject(raw_counts, 
                           project = "Elyada", 
                           min.cells = 3, 
                           min.features = 500)
pdac@meta.data$sample <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "SRR9274536", 
                                   grepl("-2", rownames(pdac@meta.data)) ~ "SRR9274537", 
                                   grepl("-3", rownames(pdac@meta.data)) ~ "SRR9274538", 
                                   grepl("-4", rownames(pdac@meta.data)) ~ "SRR9274539",
                                   grepl("-5", rownames(pdac@meta.data)) ~ "SRR9274540", 
                                   grepl("-6", rownames(pdac@meta.data)) ~ "SRR9274541", 
                                   grepl("-7", rownames(pdac@meta.data)) ~ "SRR9274542", 
                                   grepl("-8", rownames(pdac@meta.data)) ~ "SRR9274543", 
                                   grepl("-9", rownames(pdac@meta.data)) ~ "SRR9274544")
pdac@meta.data$condition <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-2", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-3", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-4", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-5", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-6", rownames(pdac@meta.data)) ~ "AdjNorm", 
                                      grepl("-7", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-8", rownames(pdac@meta.data)) ~ "AdjNorm", 
                                      grepl("-9", rownames(pdac@meta.data)) ~ "PDAC")
pdac@meta.data$sex <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-2", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-3", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-4", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-5", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-6", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-7", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-8", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-9", rownames(pdac@meta.data)) ~ "female")

Preprocessing

We run the typical single cell pre-processing steps on our cells - normalization, dimension reduction, and clustering. The t-SNE embedding looks decent, but could definitely be improved. Globally, the clusters are arranged in a blob - which isn’t very informative - though the local structure seems to have been preserved fairly well. Clusters 5 and 11 are split in two, which we would prefer not to have happen.

pdac <- PrepareData(pdac, 
                    n.variable.genes = 4000, 
                    n.PC = 20, 
                    which.dim.reduc = "tsne", 
                    initial.resolution = .5, 
                    random.seed = 629)
p0 <- DimPlot(pdac, reduction = "tsne") + 
      scale_color_manual(values = unname(tableau20())) + 
      labs(x = "t-SNE 1", y = "t-SNE 2") + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p0

## [1] "Normalizing counts using SCTransform"
## [1] "Running t-SNE on 20 principal components with perplexity = 30"
## [1] "Clustering cells in PCA space using k ~ 155 & resolution = 0.5"
## [1] "Found 13 unique clusters"

Optimize Dimension Reduction

I think the two-dimensional visualization of the cells could be improved. We’ll try using UMAP and the Fast Fourier Transform-accelerated Fit-SNE (as implemented in the openTSNE library) to improve the embedding.

UMAP

It seems like UMAP does a good job of clearly separating our clusters and preserving the global structure of the data. However, difficult to see local structure within some of the clusters due to their density, and cluster 5 is split across the 2D UMAP space.

pdac <- RunUMAP(pdac, 
                reduction = "pca", 
                dims = 1:20, 
                umap.method = "uwot", 
                n.components = 2, 
                n.epochs = 750, 
                n.neighbors = 50, 
                metric = "cosine", 
                seed.use = 629, 
                verbose = FALSE)
p1 <- DimPlot(pdac, reduction = "umap") + 
      scale_color_manual(values = unname(tableau20())) + 
      labs(x = "UMAP 1", y = "UMAP 2") + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p1

Fit-SNE

For information on how to install the openTSNE implementation of Fit-SNE and how to run the algorithm, please visit the excellent GitHub repository of Pavlin Policar.

First we’ll run a simple, standard Fit-SNE embedding. It’s necessary to make the PCA embeddings accessible by Python.

pc_df <- Embeddings(pdac, reduction = "pca")
# import data
pc_df = np.array(r.pc_df)
# run Fit-SNE
affin = PerplexityBasedNN(pc_df, perplexity=50, metric='cosine', random_state=629)
init = initialization.pca(pc_df, random_state=629)
tsne1 = TSNEEmbedding(init, affin, negative_gradient_method='fft')
embed1 = tsne1.optimize(n_iter=350, exaggeration=12, momentum=0.6) 
embed2 = embed1.optimize(n_iter=1000, momentum=0.8)

The embedding looks good, but the subclusters within clusters 5 and 11 are still clearly separated, and a small part of cluster 12 is far from the rest of the cells in the cluster.

embed <- as.matrix(py$embed2)
rownames(embed) <- colnames(pdac)
pdac@reductions$fitsne <- CreateDimReducObject(embeddings = embed, 
                                               key = "FitSNE_", 
                                               assay = "SCT", 
                                               global = TRUE)
p2 <- DimPlot(pdac, reduction = "fitsne") + 
      scale_color_manual(values = unname(tableau20())) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p2

We use the ability of Fit-SNE to consider multiple perplexities in an attempt to provide a more accurate representation of both local and global structure in our data.

affin_anneal = PerplexityBasedNN(pc_df, perplexity=150, metric='cosine', random_state=629)
tsne2 = TSNEEmbedding(init, affin_anneal, negative_gradient_method='fft')
embed3 = tsne2.optimize(n_iter=350, exaggeration=12, momentum=0.5)
embed4 = embed1.optimize(n_iter=1000, exaggeration=1, momentum=0.8)
affin_anneal.set_perplexity(30)
embed5 = embed4.optimize(n_iter=500, momentum=0.8)

The perplexity annealing hasn’t really improved or even changed the embedding much at all.

embed_multi <- as.matrix(py$embed5)
rownames(embed_multi) <- colnames(pdac)
pdac@reductions$fitsne_multi <- CreateDimReducObject(embeddings = embed_multi, 
                                                     key = "FitSNE_", 
                                                     assay = "SCT", 
                                                     global = TRUE)
p3 <- DimPlot(pdac, reduction = "fitsne_multi") + 
      scale_color_manual(values = unname(tableau20())) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p3

Finally, we’ll use a multiscale kernel to represent the data in the high-dimensional space instead of the default Gaussian. This in tandem with the multiple perplexity values will preserve as much as possible of both local and global structure.

affin_multi = Multiscale(pc_df, perplexities=[30, 200], metric='cosine', random_state=629)
tsne3 = TSNEEmbedding(init, affin_multi, negative_gradient_method='fft')
embed6 = tsne3.optimize(n_iter=450, exaggeration=12, momentum=0.6)
embed7 = embed6.optimize(n_iter=1200, exaggeration=1, momentum=0.8)

The multiscale trick doesn’t completely fix the embedding issues either, but it does clean up a bit of the noise in the plot, and it does place the subclusters in clusters 11 and 5 closer together. We’ll use this embedding going forward and make sure to examine those clusters for subgroups using SCISSORS.

embed_kern <- as.matrix(py$embed7)
rownames(embed_kern) <- colnames(pdac)
pdac@reductions$fitsne_kern<- CreateDimReducObject(embeddings = embed_kern, 
                                                   key = "FitSNE_", 
                                                   assay = "SCT", 
                                                   global = TRUE)

p4 <- DimPlot(pdac, reduction = "fitsne_kern") +
      scale_color_manual(values = unname(tableau20())) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p4

Looking at the embedding, we can see that clusters 3, 4, 5, 10, and 11 contain clear small subclusters. I’m also intrigued by the shape of cluster 8. We’ll be sure to investigate each of these in turn, and annotate the groups using marker genes.

Due to the way Seurat accesses cell embeddings, we’ll need to replace our original t-SNE dimension reduction in our Seurat object with the new Fit-SNE version. We’ll keep the original Barnes-Hut t-SNE embedding under a separate name.

pdac@reductions$bh_tsne <- pdac@reductions$tsne
pdac@reductions$tsne <- pdac@reductions$fitsne_kern

SingleR Cell Type Identification

Single Cell RNA-seq Reference Data

Here we use the SingleR package to identify broad cell types. The reference dataset we load is an sctransform-normalized version of the raw counts available in scRNAseq::BaronPancreasData(), which consists of normal pancreas cells that were sequenced and annotated by the researchers.

sc_ref <- readRDS("/Volumes/labs/Home/Jen Jen Yeh Lab/Jack/scRNAseq/Seurat/single_cell_ref_normalized.Rds")
sc_preds <- SingleR(test = data.frame(pdac@assays$SCT@data), 
                    ref = sc_ref, 
                    labels = sc_ref$label, 
                    method = "cluster", 
                    clusters = pdac$seurat_clusters, 
                    de.method = "wilcox")
pdac[["SingleR.labels.sc"]] <- sc_preds$labels[match(pdac[[]][["seurat_clusters"]], rownames(sc_preds))]
pdac$SingleR.labels.sc <- case_when(pdac$SingleR.labels.sc == "acinar" ~ "Acinar", 
                                    pdac$SingleR.labels.sc == "activated_stellate" ~ "Activated Stellate",
                                    pdac$SingleR.labels.sc == "ductal" ~ "Ductal", 
                                    pdac$SingleR.labels.sc == "macrophage" ~ "Macrophage",
                                    pdac$SingleR.labels.sc == "t_cell" ~ "T", 
                                    pdac$SingleR.labels.sc == "quiescent_stellate" ~ "Quiescent Stellate")

We can see that there’s a large immune population, as well as smaller ductal, fibroblast (denoted activated and quiescent stellate in the reference dataset), and acinar groups. These broad cell types line up with what we expected to see given the authors’ original cell cluster annotations.

p5 <- DimPlot(pdac, reduction = "tsne", group.by = "SingleR.labels.sc") + 
      scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p5

Bulk Tissue RNA-seq Reference Data

This dataset is composed of labeled & log-normalized bulk RNA-seq samples from the Human Primary Cell Atlas.

bulk_ref <- HumanPrimaryCellAtlasData()
bulk_preds <- SingleR(test = data.frame(pdac@assays$SCT@data), 
                      ref = bulk_ref, 
                      labels = bulk_ref$label.main, 
                      method = "cluster", 
                      clusters = pdac$seurat_clusters, 
                      de.method = "wilcox")
pdac[["SingleR.labels.bulk"]] <- bulk_preds$labels[match(pdac[[]][["seurat_clusters"]], 
                                                         rownames(bulk_preds))]
pdac$SingleR.labels.bulk <- case_when(pdac$SingleR.labels.bulk == "B_cell" ~ "B", 
                                      pdac$SingleR.labels.bulk == "Epithelial_cells" ~ "Epithelial", 
                                      pdac$SingleR.labels.bulk == "B_cell-" ~ "B", 
                                      pdac$SingleR.labels.bulk == "T_cells" ~ "T", 
                                      pdac$SingleR.labels.bulk == "Endothelial_cells" ~ "Endothelial", 
                                      TRUE ~ pdac$SingleR.labels.bulk)

The bulk reference gives us somewhat more granular labels for the immune cells, and confirms the identities of the ductal / epithelial and stroma clusters. We see that the clusters denoted quiescent stellate by the single cell reference are here labeled as endothelial cells, and the activated stellate cells are confirmed to be fibroblasts.

p6 <- DimPlot(pdac, reduction = "tsne", group.by = "SingleR.labels.bulk") + 
      scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p6

One shouldn’t use SingleR as the final authority for cell types, but we were able to confirm the identities of the ductal and fibroblast clusters, which is important for this dataset as the cells we are most interested in are the cancer-associated fibroblasts (CAFs).

CONICSmat CNV Estimation

Next we’ll attempt to identify malignant cells using single-cell copy number variation estimation as implemented in the CONCISmat package. Details of the GMM methodology used can be found at the Diaz Lab’s GitHub repository. Note: this step is memory-intensive because 1) it requires the sparse counts matrix to be cast to a dense matrix and 2) a lot of Gaussian mixture models get estimated. If your machine doesn’t have a lot of RAM it might be best to skip this and manually annotate the malignant cells instead through the usage of known canonical markers or the VAM single-cell GSEA methodology.

chrom_regions <- read.table("/Volumes/labs/Home/Jen Jen Yeh Lab/Jack/scRNAseq/chrom_arm_positions.txt", 
                            sep = "\t", 
                            row.names = 1, 
                            header = TRUE)
gene_pos <- getGenePositions(rownames(pdac))
cpm <- t(t(as.matrix(pdac@assays$SCT@counts)) / colSums(as.matrix(pdac@assays$SCT@counts))) * 10^5
cpm <- log2(cpm + 1)
norm_factor <- calcNormFactors(cpm)
cnv_est <- plotAll(mat = cpm, 
                   normFactor = norm_factor, 
                   regions = chrom_regions, 
                   gene_pos = gene_pos, 
                   fname = "Elyada")
## [1] "Fitting GMM for chr1 0:122026459 iteration 1"
## number of iterations= 404 
## [1] "Fitting GMM for chr1 0:122026459 iteration 2"
## number of iterations= 561 
## [1] "Fitting GMM for chr1 0:122026459 iteration 3"
## number of iterations= 437 
## [1] "Fitting GMM for chr1 0:122026459 iteration 4"
## number of iterations= 493 
## [1] 44
## [1] "Fitting GMM for chr1 124932724:248956422 iteration 1"
## number of iterations= 97 
## [1] "Fitting GMM for chr1 124932724:248956422 iteration 2"
## number of iterations= 581 
## [1] "Fitting GMM for chr1 124932724:248956422 iteration 3"
## number of iterations= 240 
## [1] "Fitting GMM for chr1 124932724:248956422 iteration 4"
## number of iterations= 515 
## [1] 44
## [1] "Fitting GMM for chr2 0:92188145 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr2 0:92188145 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr2 0:92188145 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr2 0:92188145 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr2 94090557:242193529 iteration 1"
## number of iterations= 786 
## [1] "Fitting GMM for chr2 94090557:242193529 iteration 2"
## number of iterations= 869 
## [1] "Fitting GMM for chr2 94090557:242193529 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr2 94090557:242193529 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr3 0:90772458 iteration 1"
## number of iterations= 651 
## [1] "Fitting GMM for chr3 0:90772458 iteration 2"
## number of iterations= 763 
## [1] "Fitting GMM for chr3 0:90772458 iteration 3"
## number of iterations= 697 
## [1] "Fitting GMM for chr3 0:90772458 iteration 4"
## number of iterations= 674 
## [1] 44
## [1] "Fitting GMM for chr3 93655574:198295559 iteration 1"
## number of iterations= 149 
## [1] "Fitting GMM for chr3 93655574:198295559 iteration 2"
## number of iterations= 149 
## [1] "Fitting GMM for chr3 93655574:198295559 iteration 3"
## number of iterations= 174 
## [1] "Fitting GMM for chr3 93655574:198295559 iteration 4"
## number of iterations= 144 
## [1] 44
## [1] "Fitting GMM for chr4 0:49712061 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr4 0:49712061 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr4 0:49712061 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr4 0:49712061 iteration 4"
## number of iterations= 880 
## [1] 44
## [1] "Fitting GMM for chr4 51743951:190214555 iteration 1"
## number of iterations= 427 
## [1] "Fitting GMM for chr4 51743951:190214555 iteration 2"
## number of iterations= 316 
## [1] "Fitting GMM for chr4 51743951:190214555 iteration 3"
## number of iterations= 336 
## [1] "Fitting GMM for chr4 51743951:190214555 iteration 4"
## number of iterations= 415 
## [1] 44
## [1] "Fitting GMM for chr5 0:46485900 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr5 0:46485900 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr5 0:46485900 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr5 0:46485900 iteration 4"
## number of iterations= 935 
## [1] 44
## [1] "Fitting GMM for chr5 50059807:181538259 iteration 1"
## number of iterations= 411 
## [1] "Fitting GMM for chr5 50059807:181538259 iteration 2"
## number of iterations= 597 
## [1] "Fitting GMM for chr5 50059807:181538259 iteration 3"
## number of iterations= 533 
## [1] "Fitting GMM for chr5 50059807:181538259 iteration 4"
## number of iterations= 509 
## [1] 44
## [1] "Fitting GMM for chr6 0:58553888 iteration 1"
## number of iterations= 404 
## [1] "Fitting GMM for chr6 0:58553888 iteration 2"
## number of iterations= 363 
## [1] "Fitting GMM for chr6 0:58553888 iteration 3"
## number of iterations= 788 
## [1] "Fitting GMM for chr6 0:58553888 iteration 4"
## number of iterations= 563 
## [1] 44
## [1] "Fitting GMM for chr6 59829934:170805979 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr6 59829934:170805979 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr6 59829934:170805979 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr6 59829934:170805979 iteration 4"
## number of iterations= 767 
## [1] 44
## [1] "Fitting GMM for chr7 0:58169653 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr7 0:58169653 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr7 0:58169653 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr7 0:58169653 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr7 61528020:159345973 iteration 1"
## number of iterations= 580 
## [1] "Fitting GMM for chr7 61528020:159345973 iteration 2"
## number of iterations= 507 
## [1] "Fitting GMM for chr7 61528020:159345973 iteration 3"
## number of iterations= 579 
## [1] "Fitting GMM for chr7 61528020:159345973 iteration 4"
## number of iterations= 567 
## [1] 44
## [1] "Fitting GMM for chr8 0:44033744 iteration 1"
## number of iterations= 681 
## [1] "Fitting GMM for chr8 0:44033744 iteration 2"
## number of iterations= 845 
## [1] "Fitting GMM for chr8 0:44033744 iteration 3"
## number of iterations= 782 
## [1] "Fitting GMM for chr8 0:44033744 iteration 4"
## number of iterations= 787 
## [1] 44
## [1] "Fitting GMM for chr8 45877265:145138636 iteration 1"
## number of iterations= 718 
## [1] "Fitting GMM for chr8 45877265:145138636 iteration 2"
## number of iterations= 614 
## [1] "Fitting GMM for chr8 45877265:145138636 iteration 3"
## number of iterations= 614 
## [1] "Fitting GMM for chr8 45877265:145138636 iteration 4"
## number of iterations= 614 
## [1] 44
## [1] "Fitting GMM for chr9 0:43389635 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr9 0:43389635 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr9 0:43389635 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr9 0:43389635 iteration 4"
## number of iterations= 863 
## [1] 44
## [1] "Fitting GMM for chr9 45518558:138394717 iteration 1"
## number of iterations= 655 
## [1] "Fitting GMM for chr9 45518558:138394717 iteration 2"
## number of iterations= 656 
## [1] "Fitting GMM for chr9 45518558:138394717 iteration 3"
## number of iterations= 642 
## [1] "Fitting GMM for chr9 45518558:138394717 iteration 4"
## number of iterations= 476 
## [1] 44
## [1] "Fitting GMM for chr10 0:39686682 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr10 0:39686682 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr10 0:39686682 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr10 0:39686682 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr10 41593521:133797422 iteration 1"
## number of iterations= 588 
## [1] "Fitting GMM for chr10 41593521:133797422 iteration 2"
## number of iterations= 525 
## [1] "Fitting GMM for chr10 41593521:133797422 iteration 3"
## number of iterations= 640 
## [1] "Fitting GMM for chr10 41593521:133797422 iteration 4"
## number of iterations= 555 
## [1] 44
## [1] "Fitting GMM for chr11 0:51078348 iteration 1"
## number of iterations= 236 
## [1] "Fitting GMM for chr11 0:51078348 iteration 2"
## number of iterations= 293 
## [1] "Fitting GMM for chr11 0:51078348 iteration 3"
## number of iterations= 294 
## [1] "Fitting GMM for chr11 0:51078348 iteration 4"
## number of iterations= 158 
## [1] 44
## [1] "Fitting GMM for chr11 54425074:135086622 iteration 1"
## number of iterations= 977 
## [1] "Fitting GMM for chr11 54425074:135086622 iteration 2"
## number of iterations= 862 
## [1] "Fitting GMM for chr11 54425074:135086622 iteration 3"
## number of iterations= 870 
## [1] "Fitting GMM for chr11 54425074:135086622 iteration 4"
## number of iterations= 892 
## [1] 44
## [1] "Fitting GMM for chr12 0:34769407 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr12 0:34769407 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr12 0:34769407 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr12 0:34769407 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr12 37185252:133275309 iteration 1"
## number of iterations= 887 
## [1] "Fitting GMM for chr12 37185252:133275309 iteration 2"
## number of iterations= 768 
## [1] "Fitting GMM for chr12 37185252:133275309 iteration 3"
## number of iterations= 969 
## [1] "Fitting GMM for chr12 37185252:133275309 iteration 4"
## number of iterations= 878 
## [1] 44
## [1] "Fitting GMM for chr13 18051248:114364328 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr13 18051248:114364328 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr13 18051248:114364328 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr13 18051248:114364328 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr14 18173523:107043718 iteration 1"
## number of iterations= 525 
## [1] "Fitting GMM for chr14 18173523:107043718 iteration 2"
## number of iterations= 547 
## [1] "Fitting GMM for chr14 18173523:107043718 iteration 3"
## number of iterations= 392 
## [1] "Fitting GMM for chr14 18173523:107043718 iteration 4"
## number of iterations= 429 
## [1] 44
## [1] "Fitting GMM for chr15 19725254:101991189 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr15 19725254:101991189 iteration 2"
## number of iterations= 911 
## [1] "Fitting GMM for chr15 19725254:101991189 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr15 19725254:101991189 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr16 0:36311158 iteration 1"
## number of iterations= 862 
## [1] "Fitting GMM for chr16 0:36311158 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr16 0:36311158 iteration 3"
## number of iterations= 747 
## [1] "Fitting GMM for chr16 0:36311158 iteration 4"
## number of iterations= 929 
## [1] 44
## [1] "Fitting GMM for chr16 36334460:90338345 iteration 1"
## number of iterations= 745 
## [1] "Fitting GMM for chr16 36334460:90338345 iteration 2"
## number of iterations= 770 
## [1] "Fitting GMM for chr16 36334460:90338345 iteration 3"
## number of iterations= 663 
## [1] "Fitting GMM for chr16 36334460:90338345 iteration 4"
## number of iterations= 853 
## [1] 44
## [1] "Fitting GMM for chr17 0:22813679 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr17 0:22813679 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr17 0:22813679 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr17 0:22813679 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr17 26566633:83257441 iteration 1"
## number of iterations= 900 
## [1] "Fitting GMM for chr17 26566633:83257441 iteration 2"
## number of iterations= 652 
## [1] "Fitting GMM for chr17 26566633:83257441 iteration 3"
## number of iterations= 838 
## [1] "Fitting GMM for chr17 26566633:83257441 iteration 4"
## number of iterations= 661 
## [1] 44
## [1] "Fitting GMM for chr18 20861206:80373285 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr18 20861206:80373285 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr18 20861206:80373285 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr18 20861206:80373285 iteration 4"
## number of iterations= 161 
## [1] 44
## [1] "Fitting GMM for chr19 0:24498980 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr19 0:24498980 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr19 0:24498980 iteration 3"
## number of iterations= 894 
## [1] "Fitting GMM for chr19 0:24498980 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr19 27190874:58617616 iteration 1"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr19 27190874:58617616 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr19 27190874:58617616 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr19 27190874:58617616 iteration 4"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] 44
## [1] "Fitting GMM for chr20 0:26436232 iteration 1"
## number of iterations= 908 
## [1] "Fitting GMM for chr20 0:26436232 iteration 2"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr20 0:26436232 iteration 3"
## WARNING! NOT CONVERGENT! 
## number of iterations= 1000 
## [1] "Fitting GMM for chr20 0:26436232 iteration 4"
## number of iterations= 846 
## [1] 44
## [1] "Fitting GMM for chr20 30038348:64444167 iteration 1"
## number of iterations= 331 
## [1] "Fitting GMM for chr20 30038348:64444167 iteration 2"
## number of iterations= 307 
## [1] "Fitting GMM for chr20 30038348:64444167 iteration 3"
## number of iterations= 451 
## [1] "Fitting GMM for chr20 30038348:64444167 iteration 4"
## number of iterations= 313 
## [1] 44
## [1] "Fitting GMM for chr21 12915808:46709983 iteration 1"
## number of iterations= 444 
## [1] "Fitting GMM for chr21 12915808:46709983 iteration 2"
## number of iterations= 804 
## [1] "Fitting GMM for chr21 12915808:46709983 iteration 3"
## number of iterations= 587 
## [1] "Fitting GMM for chr21 12915808:46709983 iteration 4"
## number of iterations= 755 
## [1] 44
## [1] "Fitting GMM for chr22 15054318:50818468 iteration 1"
## number of iterations= 657 
## [1] "Fitting GMM for chr22 15054318:50818468 iteration 2"
## number of iterations= 786 
## [1] "Fitting GMM for chr22 15054318:50818468 iteration 3"
## number of iterations= 720 
## [1] "Fitting GMM for chr22 15054318:50818468 iteration 4"
## number of iterations= 971 
## [1] 44

Visualizing CNVs

After estimating CNVs, we cluster the cells into \(k = 3\) clusters, with the hope of finding one large cluster of normal cells and two smaller clusters composed of CAFs and PDAC cells.

bic_table <- read.table("./Elyada_BIC_LR.txt", 
                        sep = "\t", 
                        row.names = 1, 
                        header = TRUE, 
                        check.names = FALSE)
cand_regions <- rownames(bic_table[bic_table$`BIC difference` > 1000 & bic_table$`LRT adj. p-val` < .01, ])
hist1 <- plotHistogram(cnv_est[, cand_regions], 
                       cpm, 
                       clusters = 3, 
                       zscoreThreshold = 3, 
                       celltypes = pdac$SingleR.labels.bulk, 
                       patients = pdac$sample)

We add the normal vs. malignant cell labels in to our Seurat object’s metadata, then visualize the results. As expected, the malignant cells are located in the clusters identified by SingleR as ductal cells and fibroblasts. This indicates that CONICSmat did a solid job of estimating the CNVs - no easy feat with sparse, noisy single-cell data.

normal <- which(hist1 == 2)
malignant <- which(hist1 != 2)
pdac@meta.data$malig <- ifelse(rownames(pdac@meta.data) %in% names(normal), "Normal", "Malignant")
p7 <- DimPlot(pdac, reduction = "tsne", group.by = "malig") + 
      scale_color_manual(values = wes_palette("Zissou1", n = 5)[c(5, 2)]) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p7

##             used   (Mb) gc trigger    (Mb) limit (Mb)   max used    (Mb)
## Ncells   8277599  442.1   51747732  2763.7         NA   31066857  1659.2
## Vcells 269765466 2058.2 1666358438 12713.4      16384 2082948016 15891.7

DECODER

Next, we use Dr. Xianlu Peng’s DECODER in order to deconvolve the dataset and assign weights to each cell using non-negative matrix factorization. We calculate basal & classical PDAC, normal & activated stroma, immune, and endocrine & exocrine pancreas compartment weights.

sample_wts_unscaled <- Decon_single_sample("TCGA_RNAseq_PAAD", pdac@assays$SCT@data, "geneSymbol")
sample_wts <- Norm_PDAC_weights(sample_wts_unscaled)
pdac <- AddMetaData(pdac, sample_wts$Immune, "immune")
pdac <- AddMetaData(pdac, sample_wts$bcRatio, "bc_ratio")
pdac <- AddMetaData(pdac, sample_wts$Exocrine, "exocrine")
pdac <- AddMetaData(pdac, sample_wts$Endocrine, "endocrine")
pdac <- AddMetaData(pdac, sample_wts_unscaled[, 9], "basal")
pdac <- AddMetaData(pdac, sample_wts_unscaled[, 5], "classical")
pdac <- AddMetaData(pdac, sample_wts$NormalStroma, "norm_stroma")
pdac <- AddMetaData(pdac, sample_wts$ActivatedStroma, "act_stroma")

Visualizing DECODER Weights

Basal PDAC

The basal weights are highest in a subcluster of the ductal group identified through SingleR. This is interesting as the authors did not find evidence of the basal subtype in their paper.

p8 <- FeaturePlot(pdac, reduction = "tsne", features = "basal") + 
      scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      NoLegend()
p8

Classical PDAC

The classical weights are highest in another subcluster of the ductal cluster, and cells with high classical weights do not collocate with those that have high basal weights. The putative classical and basal PDAC cells also align closely with the cells identified through CONCISmat as malignant.

p9 <- FeaturePlot(pdac, reduction = "tsne", features = "classical") + 
      scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      NoLegend()
p9

Exocrine Pancreas

The cluster identified through SingleR as acinar cells is the only cluster with high exocrine pancreas weights.

p10 <- FeaturePlot(pdac, reduction = "tsne", features = "exocrine") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p10

Endocrine Pancreas

No cells have high endocrine pancreas weights.

p11 <- FeaturePlot(pdac, reduction = "tsne", features = "endocrine") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p11

Immune

Once again, we confirm the largeness of the immune cell population in this dataset.

p12 <- FeaturePlot(pdac, reduction = "tsne", features = "immune") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p12

Normal Stroma

Cells with high normal stroma stroma weights are located in the cluster identified by SingleR as being composed of endothelial cells.

p13 <- FeaturePlot(pdac, reduction = "tsne", features = "norm_stroma") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p13

Activated Stroma

Cells with high activated stroma weights are also located in the fibroblast cluster, and do not intersect with the cells that have high normal stroma scores. This indicates that SCISSORS will most likely perform well on the fibroblast cluster and be able to quickly tease out the cell subtypes.

p14 <- FeaturePlot(pdac, reduction = "tsne", features = "act_stroma") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p14

SCISSORS

Now that we have rough labels from SingleR, CNVs from CONICSmat, and compartment weights from DECODER, we should have more than enough cell-level metadata to look for and annotate cell subtypes using SCISSORS.

Fibroblasts

The fibroblast marker genes provided by Elyada et al match the SingleR results defining cluster 8 as containing fibroblasts.

p15 <- FeaturePlot(pdac, reduction = "tsne", features = "COL1A1") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "COL1A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p16 <- FeaturePlot(pdac, reduction = "tsne", features = "COL3A1") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "COL3A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p17 <- FeaturePlot(pdac, reduction = "tsne", features = "LUM") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "LUM") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p18 <- FeaturePlot(pdac, reduction = "tsne", features = "DCN") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "DCN") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p15 | p16) / (p17 | p18)

Reclustering

Here we use ReclusterCells() to identify subclusters within cluster 7. We find four distinct subclusters.

fibro <- ReclusterCells(pdac,
                        which.clust = 8,
                        n.variable.genes = 4000, 
                        n.PC = 20, 
                        resolution.vals = c(.1, .2, .3, .4), 
                        k.vals = c(5, 10, 20, 30), 
                        which.dim.reduc = "tsne", 
                        redo.embedding = TRUE, 
                        do.plot = FALSE)
fibro_pc <- Embeddings(fibro, "pca")
## [1] "Reclustering cells in cluster 8 using k = 20 & resolution = 0.1, which achieved silhouette score: 0.536"

We’ll again run Fit-SNE on the reclustered cells, for consistencies sake.

# import data
fibro_pc = r.fibro_pc
# run Fit-SNE
affin_fibro = PerplexityBasedNN(fibro_pc, perplexity=40, metric='cosine', random_state=629)
init = initialization.pca(fibro_pc, random_state=629)
tsne_f = TSNEEmbedding(init, affin_fibro, negative_gradient_method='fft')
embed_f1 = tsne_f.optimize(n_iter=250, exaggeration=5, momentum=0.4) 
embed_f2 = embed_f1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

Pulling the results back into R and visualizing them shows clear separation between the subclusters. There’s some noise in subcluster 0, but other than that the reembedding looks solid.

embed_fibro <- as.matrix(py$embed_f2)
rownames(embed_fibro) <- colnames(fibro)
fibro@reductions$bh_tsne <- fibro@reductions$tsne
fibro@reductions$tsne<- CreateDimReducObject(embeddings = embed_fibro, 
                                             key = "FitSNE_", 
                                             assay = "SCT", 
                                             global = TRUE)
p19 <- DimPlot(fibro, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p19

Cell Type Identification

Next, we use the VAM method of single cell gene set enrichment analysis to determine which clusters are enriched for the iCAF and myCAF marker genes, as well as the general pan-CAF marker set. We use the marker genes identified by the authors.

icaf_genes <- c("IL6", "PDGFRA", "CXCL12", "CFD", "LMNA", 
                "AGTR1", "HAS1", "CXCL1", "CXCL2", "CCL2", "IL8")
mycaf_genes <- c("ACTA2", "TAGLN", "MMP11", "MYL9", 
                 "HOPX", "POSTN", "TPM1", "TPM2")
pan_caf_genes <- c("COL1A1", "FAP", "PDPN", "DCN", "VIM")
gene_sets <- list(icaf_genes, mycaf_genes, pan_caf_genes)
names(gene_sets) <- c("iCAF", "myCAF", "Pan-CAF")
for (i in seq(gene_sets)) {
  gene_sets[[i]] <- gene_sets[[i]][gene_sets[[i]] %in% rownames(fibro)]
}
fibro <- vamForSeurat(fibro, 
                      gene.set.collection = gene_sets, 
                      gamma = TRUE)
DefaultAssay(fibro) <- "VAMcdf"

iCAFs & myCAFs

We can easily define cluster 0 as the myCAF population, and clusters 1 and 2 as the slightly smaller iCAF population. Interestingly, cluster 3 shows no enrichment whatsoever for either the iCAF or myCAF gene sets.

p20 <- FeaturePlot(fibro, reduction = "tsne", features = "iCAF") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "iCAF Enrichment") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p21 <- FeaturePlot(fibro, reduction = "tsne", features = "myCAF") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "myCAF Enrichment") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p20 | p21) / p19

apCAFs

Interestingly, we have a small cluster of 22 cells that does not appear to express any of the fibroblast, CAF, perivascular, or endothelial markers. We’ll use differential expression testing to find out what makes it unique, and hopefully annotate it. After performing differential expression analysis, we found that the top 3 markers for cluster 4 are CLU, CD74, and CRYAB. Interestingly, CLU and CD74 were found to be differentially expressed in the apCAF population discovered in the KPC mouse models of CAFs in Elyada et al.

DefaultAssay(fibro) <- "SCT"
fibro_markers <- FindAllMarkers(fibro, 
                                assay = "SCT", 
                                logfc.threshold = 1.5, 
                                test.use = "wilcox", 
                                only.pos = TRUE, 
                                random.seed = 629, 
                                verbose = FALSE)
fibro_markers %>% 
  filter(cluster == 4) %>% 
  arrange(desc(avg_logFC))
p_val avg_logFC pct.1 pct.2 p_val_adj cluster gene

We re-run GSEA, again using the VAM package and the differentially expressed genes for the apCAF population as defined in Elyada et al (with the mouse gene names converted to HGNC symbols). We can see that the apCAF pathway is strongly enriched in cluster 3 as compared to the other CAF clusters.

apcaf_genes <- c("HLA-DQB1", "CD74", "SAA3P", "SLPI")
gene_sets <- list(icaf_genes, mycaf_genes, apcaf_genes, pan_caf_genes)
names(gene_sets) <- c("iCAF", "myCAF", "apCAF", "Pan-CAF")
for (i in seq(gene_sets)) {
  gene_sets[[i]] <- gene_sets[[i]][gene_sets[[i]] %in% rownames(fibro)]
}
fibro <- vamForSeurat(fibro, 
                      gene.set.collection = gene_sets, 
                      gamma = TRUE)
DefaultAssay(fibro) <- "VAMcdf"
p22 <- FeaturePlot(fibro, reduction = "tsne", features = "apCAF") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "apCAF Enrichment") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p22 / p19

Visualization

Finally, we add cell labels to our identified clusters.

fibro$label <- case_when(fibro$seurat_clusters == 0 ~ "myCAF", 
                         fibro$seurat_clusters == 1 ~ "iCAF", 
                         fibro$seurat_clusters == 2 ~ "iCAF", 
                         fibro$seurat_clusters == 3 ~ "apCAF")
p23 <- DimPlot(fibro, reduction = "tsne", group.by = "label") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank())
p23

Normal Stroma Cells

We hypothesize that the cluster identified as endothelial cells by SingleR contains our normal stroma population, and potentially some other cell types as it contains visible subclusters.

Reclustering

endo <- ReclusterCells(pdac, 
                       which.clust = 12, 
                       n.variable.genes = 4000, 
                       n.PC = 20, 
                       which.dim.reduc = "tsne", 
                       redo.embedding = TRUE, 
                       random.seed = 629)
endo_pc <- Embeddings(endo, "pca")
## [1] "Reclustering cells in cluster 12 using k = 50 & resolution = 0.1, which achieved silhouette score: 0.425"

For consistencies’ sake, we’ll run Fit-SNE on the reclustered object.

# import data
endo_pc = r.endo_pc
# run Fit-SNE
affin_endo = PerplexityBasedNN(endo_pc, perplexity=60, metric='cosine', random_state=629)
init = initialization.pca(endo_pc, random_state=629)
tsne_e = TSNEEmbedding(init, affin_endo, negative_gradient_method='fft')
embed_e1 = tsne_e.optimize(n_iter=250, exaggeration=10, momentum=0.6) 
embed_e2 = embed_e1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
embed_endo <- as.matrix(py$embed_e2)
rownames(embed_endo) <- colnames(endo)
endo@reductions$bh_tsne <- endo@reductions$tsne
endo@reductions$tsne<- CreateDimReducObject(embeddings = embed_endo, 
                                            key = "FitSNE_", 
                                            assay = "SCT", 
                                            global = TRUE)
p24 <- DimPlot(endo, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p24

Perivascular Cells

By examining the marker genes provided in the Elyada paper, we define cluster 0 as being composed of perivascular cells.

p25 <- FeaturePlot(endo, reduction = "tsne", features = "IGFBP7") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "IGFBP7") + 
       theme_yehlab() + 
       NoLegend() +
       theme(axis.title = element_blank())
p26 <- FeaturePlot(endo, reduction = "tsne", features = "ACTA2") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "ACTA2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p27 <- FeaturePlot(endo, reduction = "tsne", features = "RGS5") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "RGS5") + 
       theme_yehlab() + 
       NoLegend() +
       theme(axis.title = element_blank())
(p25 | p26 | p27) / p24

Endothelial Cells

Next, we use the gene markers PLVAP and VWF (again provided in Elyada et al) to identify cluster 1 as the endothelial cells.

p28 <- FeaturePlot(endo, reduction = "tsne", features = "PLVAP") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "PLVAP") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p29 <- FeaturePlot(endo, reduction = "tsne", features = "VWF") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "VWF") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p28 | p29) / p24

Visualization

First we add labels to our two clusters, then we visualize the results.

endo$label <- case_when(endo$seurat_clusters == 0 ~ "Perivascular", 
                        endo$seurat_clusters == 1 ~ "Endothelial")
p30 <- DimPlot(endo, reduction = "tsne", group.by = "label") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank())
p30

T Cells

Going back to the main Seurat object, we should have a large population of T and NK cells that warrants further investigation. Using CD3D expression we can easily identify clusters 0, 3, and 7 as the mixed T & NK cells. We already see some good separation, so reclustering the cells should have good results.

p31 <- FeaturePlot(pdac, reduction = "tsne", features = "CD3D") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p31 / p4

Tumor

nkt_tumor <- subset(pdac, subset = seurat_clusters %in% c(0, 3, 7) & condition == "PDAC")

Reclustering

Here we run ReclusterCells(), while treating the NK & T cell clusters as one large group. This will hopefully allow use to elucidate T cell subtypes. We use fewer PCs for these cells since the differences between immune cells are subtle, and adding more PCs will most likely only contribute noise to our analyses.

nkt_tumor <- ReclusterCells(nkt_tumor, 
                            which.clust = list(0, 3, 7), 
                            merge.clusters = TRUE, 
                            n.variable.genes = 4000, 
                            n.PC = 15, 
                            k.vals = c(30, 40, 50, 60), 
                            resolution.vals = c(.1, .2, .3), 
                            which.dim.reduc = "tsne", 
                            redo.embedding = TRUE, 
                            random.seed = 629)
nkt_tumor_pc <- Embeddings(nkt_tumor, "pca")
## [1] "Reclustering cells in cluster 0 using k = 30 & resolution = 0.3, which achieved silhouette score: 0.455"

Once again we’ll run Fit-SNE on the reclustered cells.

# import data
nkt_tumor_pc = r.nkt_tumor_pc
# run Fit-SNE
affin_nkt_tumor = PerplexityBasedNN(nkt_tumor_pc, perplexity=180, metric='cosine', random_state=629)
init = initialization.pca(nkt_tumor_pc, random_state=629)
tsne_nkt_tumor = TSNEEmbedding(init, affin_nkt_tumor, negative_gradient_method='fft')
embed_nkt_tumor1 = tsne_nkt_tumor.optimize(n_iter=250, exaggeration=4, momentum=0.6) 
embed_nkt_tumor2 = embed_nkt_tumor1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
affin_nkt_tumor.set_perplexity(75)
embed_nkt_tumor3 = embed_nkt_tumor2.optimize(n_iter=3, exaggeration=2, momentum=0.1)
embed_nkt_tumor4 = embed_nkt_tumor3.optimize(n_iter=500, exaggeration=1, momentum=0.6)

The reembedding isn’t perfect, which we somewhat expected as immune cells are difficult to tell apart based on the transcriptome alone.

embed_nkt_tumor <- as.matrix(py$embed_nkt_tumor4)
rownames(embed_nkt_tumor) <- colnames(nkt_tumor)
nkt_tumor@reductions$bh_tsne <- nkt_tumor@reductions$tsne
nkt_tumor@reductions$tsne<- CreateDimReducObject(embeddings = embed_nkt_tumor, 
                                                 key = "FitSNE_", 
                                                 assay = "SCT", 
                                                 global = TRUE)
p32 <- DimPlot(nkt_tumor, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p32

Cell Type Identification

CD4+ T

CLusters 0 and 1 contain our CD4+ T cells, which we characterize using IL7R as we did in the PBMC3k vignette. It’s somewhat outside of our scope here to determine which subtype each cluster belongs to, so we’ll simply assign both clusters the same label and move on.

p33 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "IL7R") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p34 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD69") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p33 | p34) / p32

T-regs

Cluster 3 contains the regulatory T cells.

p35 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "IL2RA") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p36 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "FOXP3") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p35 | p36) / p32

Proliferating T-regs

We can find the proliferating T-regs in cluster 7.

p37 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "TOP2A") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p37 / p32

Mast

Mast cells can be identified using TPSAB1 expression in cluster 6.

p38 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "TPSAB1") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p38 / p32

NK

NKG7 and PRF1 show us the NK cells in cluster 5.

p39 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "NKG7") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p40 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "PRF1") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p39 | p40) / p32

CD8+ T

We use CD8A and CD2 to reveal the CD8+ T cells within clusters 2 and 4.

p41 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD8A") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p42 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD2") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p41 | p42) / p32

Intermediate Monocyte

Lastly, we have cluster 8, which doesn’t highly express our pan-T/NK cell markers CD3D and CD2. It could be a myeloid cell cluster that was mistakenly grouped with the T/NK cells. We’ll start with a Wilcoxon test to determine its differentially expressed genes.

clust8_markers <- FindAllMarkers(nkt_tumor, 
                                 test.use = "wilcox",
                                 min.diff.pct = .2,
                                 logfc.threshold = .5, 
                                 verbose = FALSE, 
                                 random.seed = 629) %>% 
                  filter(cluster == 8, p_val_adj < .05) %>% 
                  arrange(desc(1 - p_val_adj)) %>% 
                  print()
##                    p_val avg_logFC pct.1 pct.2     p_val_adj cluster     gene
## SPI1       1.276127e-117 0.6394855 0.500 0.015 1.913808e-113       8     SPI1
## TMEM176B.1  1.951396e-81 0.7020478 0.525 0.025  2.926509e-77       8 TMEM176B
## AIF1        5.975173e-61 1.0496310 0.675 0.060  8.960966e-57       8     AIF1
## MS4A6A      1.077447e-49 0.6118500 0.425 0.028  1.615847e-45       8   MS4A6A
## C1QA        4.494148e-41 1.0151405 0.500 0.048  6.739873e-37       8     C1QA
## CST3.1      4.909324e-41 1.3989825 0.700 0.101  7.362513e-37       8     CST3
## CEBPD       3.107994e-39 0.5168535 0.500 0.048  4.661059e-35       8    CEBPD
## C1QC        4.910297e-37 1.0911696 0.425 0.038  7.363972e-33       8     C1QC
## LST1        5.979516e-36 0.7781232 0.625 0.084  8.967481e-32       8     LST1
## GRN         1.074343e-33 0.5834286 0.600 0.082  1.611192e-29       8      GRN
## HLA-DRB5    9.274134e-33 0.9552109 0.775 0.152  1.390842e-28       8 HLA-DRB5
## HLA-DQA1    9.993726e-32 1.0629547 0.700 0.125  1.498759e-27       8 HLA-DQA1
## HLA-DRB1.2  5.443325e-30 1.5532245 0.975 0.292  8.163354e-26       8 HLA-DRB1
## HLA-DRA.1   1.158221e-29 2.2121810 0.950 0.409  1.736985e-25       8  HLA-DRA
## HLA-DMB     4.386335e-29 0.5408872 0.475 0.058  6.578186e-25       8  HLA-DMB
## TYROBP.2    3.246406e-27 1.1379201 0.700 0.141  4.868635e-23       8   TYROBP
## KLF4        1.527066e-25 0.7371558 0.375 0.042  2.290141e-21       8     KLF4
## C1QB        2.688702e-24 0.9941321 0.400 0.051  4.032246e-20       8     C1QB
## FCER1G.2    1.827197e-23 0.8256689 0.550 0.097  2.740247e-19       8   FCER1G
## HLA-DQA2    2.113476e-23 0.5648281 0.375 0.045  3.169581e-19       8 HLA-DQA2
## HLA-DPB1    6.539129e-23 1.5900322 0.900 0.387  9.806732e-19       8 HLA-DPB1
## CD74.3      7.169626e-23 1.9170476 0.975 0.724  1.075229e-18       8     CD74
## LYZ         2.281872e-22 1.3494472 0.550 0.107  3.422123e-18       8      LYZ
## HLA-DQB1    4.352556e-22 1.1332910 0.700 0.188  6.527528e-18       8 HLA-DQB1
## PLAUR.1     1.321580e-21 0.5098414 0.400 0.056  1.981974e-17       8    PLAUR
## HLA-DMA     1.559863e-20 0.6523222 0.575 0.121  2.339327e-16       8  HLA-DMA
## HLA-DPA1.1  2.353354e-20 1.4657017 0.850 0.368  3.529325e-16       8 HLA-DPA1
## NPC2        7.072958e-18 0.6875523 0.625 0.162  1.060731e-13       8     NPC2
## CD83        2.621481e-16 0.8046446 0.700 0.214  3.931435e-12       8     CD83
## TYMP        1.904906e-12 0.5372419 0.725 0.266  2.856788e-08       8     TYMP
## APOE.1      5.771981e-11 0.6848562 0.300 0.061  8.656241e-07       8     APOE
## CXCL8       6.271403e-11 0.5556395 0.250 0.042  9.405223e-07       8    CXCL8
## LGALS1.2    1.515934e-10 0.7172623 0.725 0.319  2.273447e-06       8   LGALS1
## GLUL.1      2.783779e-10 0.5003458 0.475 0.146  4.174833e-06       8     GLUL
## IER3        1.476494e-09 0.5731977 0.400 0.115  2.214298e-05       8     IER3
## GSTP1       1.868260e-08 0.6851803 0.550 0.240  2.801829e-04       8    GSTP1
## ATF3        2.529892e-08 0.7294797 0.525 0.187  3.794079e-04       8     ATF3
## S100A11.2   2.753010e-08 0.6309440 0.725 0.429  4.128689e-04       8  S100A11
## SAT1        8.290989e-08 0.9010269 0.900 0.662  1.243400e-03       8     SAT1
## PSAP        2.522505e-07 0.5706095 0.625 0.332  3.783000e-03       8     PSAP
## PNRC1.1     3.015767e-06 0.5040474 0.850 0.632  4.522746e-02       8    PNRC1

Interestingly, several intermediate monocyte markers - LYZ, HLA-DRA, CD74, and HLA-DPB1 - are differentially expressed in cluster 8.

We’ll plot some of those markers below.

p43 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "LYZ") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p44 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "HLA-DRA") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p45 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD74") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p46 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "HLA-DPB1") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
((p43 | p44) / (p45 | p46)) / p32

Visualization

We add labels to our T cell Seurat object and visualize the results.

nkt_tumor$label <- case_when(nkt_tumor$seurat_clusters == 0 ~ "CD4+ T", 
                             nkt_tumor$seurat_clusters == 1 ~ "CD4+ T", 
                             nkt_tumor$seurat_clusters == 2 ~ "CD8+ T", 
                             nkt_tumor$seurat_clusters == 3 ~ "T-reg", 
                             nkt_tumor$seurat_clusters == 4 ~ "CD8+ T", 
                             nkt_tumor$seurat_clusters == 5 ~ "NK", 
                             nkt_tumor$seurat_clusters == 6 ~ "Mast", 
                             nkt_tumor$seurat_clusters == 7 ~ "Proliferating T-reg", 
                             nkt_tumor$seurat_clusters == 8 ~ "Intermediate Monocyte")
p47 <- DimPlot(nkt_tumor, reduction = "tsne", group.by = "label") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p47

Adjacent Normal

nkt_norm <- subset(pdac, subset = seurat_clusters %in% c(0, 3, 7) & condition == "AdjNorm")

Reclustering

nkt_norm <- ReclusterCells(nkt_norm, 
                           which.clust = list(0, 3, 7), 
                           merge.clusters = TRUE, 
                           n.variable.genes = 4000, 
                           n.PC = 10, 
                           k.vals = c(5, 10, 15, 20), 
                           resolution.vals = c(.1, .2, .3), 
                           which.dim.reduc = "tsne", 
                           redo.embedding = TRUE, 
                           random.seed = 629)
nkt_norm_pc <- Embeddings(nkt_norm, "pca")
## [1] "Reclustering cells in cluster 0 using k = 10 & resolution = 0.3, which achieved silhouette score: 0.439"

As with the other reclusterings, we’ll run Fit-SNE in order to (hopefully) obtain a better low-dimensional embedding of our cells.

# import data
nkt_norm_pc = r.nkt_norm_pc
# run Fit-SNE
affin_nkt_norm = PerplexityBasedNN(nkt_norm_pc, perplexity=100, metric='cosine', random_state=629)
init = initialization.pca(nkt_norm_pc, random_state=629)
tsne_nkt_norm = TSNEEmbedding(init, affin_nkt_norm, negative_gradient_method='fft')
embed_nkt_norm1 = tsne_nkt_norm.optimize(n_iter=250, exaggeration=12, momentum=0.6) 
embed_nkt_norm2 = embed_nkt_norm1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
affin_nkt_norm.set_perplexity(20)
embed_nkt_norm3 = embed_nkt_norm2.optimize(n_iter=20, exaggeration=2, momentum=0.7)
embed_nkt_norm4 = embed_nkt_norm3.optimize(n_iter=500)
embed_nkt_norm <- as.matrix(py$embed_nkt_norm4)
rownames(embed_nkt_norm) <- colnames(nkt_norm)
nkt_norm@reductions$bh_tsne <- nkt_norm@reductions$tsne
nkt_norm@reductions$tsne<- CreateDimReducObject(embeddings = embed_nkt_norm, 
                                                key = "FitSNE_", 
                                                assay = "SCT", 
                                                global = TRUE)
p48 <- DimPlot(nkt_norm, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p48

Cell Type Identification

First we’ll use a Wilcoxon test to determine which genes characterize each cluster.

nkt_norm_markers <- FindAllMarkers(nkt_norm, 
                                   logfc.threshold = .5, 
                                   min.diff.pct = .2, 
                                   verbose = FALSE, 
                                   only.pos = TRUE, 
                                   random.seed = 629) %>% 
                    filter(p_val_adj < .05)
nkt_norm_markers  %>% 
  group_by(cluster) %>% 
  top_n(n = 2, wt = avg_logFC)
p_val avg_logFC pct.1 pct.2 p_val_adj cluster gene
0 1.1374536 0.805 0.283 0.0e+00 0 KLRB1
0 0.6289870 0.893 0.586 0.0e+00 0 IL7R
0 1.1797617 0.936 0.309 0.0e+00 1 GZMK
0 0.5931411 0.806 0.444 0.0e+00 1 CST7
0 0.6538218 0.450 0.047 0.0e+00 2 KLRC1
0 0.9775093 0.535 0.119 0.0e+00 2 GNLY
0 1.6999634 0.798 0.085 0.0e+00 3 GZMB
0 1.8534674 0.685 0.144 0.0e+00 3 GNLY
0 0.7129245 0.642 0.076 0.0e+00 4 SELL
0 0.6277972 0.593 0.102 0.0e+00 4 CCR7
0 1.1823501 0.663 0.041 0.0e+00 5 TNFRSF4
0 1.1552110 0.894 0.470 0.0e+00 5 LTB
0 1.5419795 0.453 0.048 0.0e+00 6 AREG
0 0.8713618 0.660 0.191 0.0e+00 6 TYROBP
0 2.0733590 1.000 0.309 0.0e+00 7 TUBA1B
0 2.1312287 1.000 0.423 3.4e-06 7 HMGB2
CD4+ T

We can use IL7R and S100A4 expression to identify the memory CD4+ T cells in cluster 0. IL7R and CCR7 identify the naive CD4+ T cells in the adjacent cluster 4.

p49 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "IL7R") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p50 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "S100A4") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p51 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "CCR7") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p50 | p49 | p51) / p48

CD8+ T

Next we reveal the CD8+ T cells in clusters 1 and 2 with CD8A, as per usual.

p52 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "CD8A") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p52 / p48

T-reg

The T-reg cluster, cluster 5, is identified using TIGIT and FOXP3.

p53 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "TIGIT") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p54 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "FOXP3") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p53 | p54) / p48

NK

The natural killers can be found in cluster 4 through their expression of PRF1 and NKG7. The NKG7 expression also confirms the identities of the CD8+ T cells we just annotated.

p55 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "PRF1") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p56 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "NKG7") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p55 | p56) / p48

Proliferating T-reg

The tiny proliferating T-reg population in cluster 7 is characterized by TOP2A.

p57 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "TOP2A") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p57 / p48

Intermediate Monocyte

After running another Wilcoxon differential expression test specifically for the last cluster, cluster 6, we can see that several of the myeloid marker genes from Elyada et al are upregulated - CD68, LYZ, CD14, HLA-DRA. LST1 is also significantly differentially expressed; LST1 is involved in monocyte differentiation. Lastly, TYROBP, aka DAP12, is associated with inflammation and is highly expressed in activated monocytes.

FindMarkers(nkt_norm, 
            ident.1 = 6, 
            only.pos = TRUE, 
            min.pct = .3, 
            verbose = FALSE, 
            random.seed = 629) %>% 
  filter(p_val_adj < .05) 
p_val avg_logFC pct.1 pct.2 p_val_adj
AREG 0.0e+00 1.5419795 0.453 0.048 0.0000000
CD68 0.0e+00 0.3393221 0.340 0.034 0.0000000
CCDC88A 0.0e+00 0.2926852 0.340 0.038 0.0000000
GRN 0.0e+00 0.4770964 0.453 0.075 0.0000000
LST1 0.0e+00 0.7170228 0.509 0.099 0.0000000
TYROBP 0.0e+00 0.8713618 0.660 0.191 0.0000000
LMO4 0.0e+00 0.3398349 0.396 0.079 0.0000000
LTC4S 0.0e+00 0.4283473 0.302 0.050 0.0000000
FCER1G 0.0e+00 0.5973548 0.547 0.184 0.0000000
IFITM3 0.0e+00 0.3271327 0.321 0.066 0.0000000
AIF1 0.0e+00 0.6072226 0.453 0.137 0.0000000
APOC1 0.0e+00 0.3694114 0.340 0.079 0.0000001
CD14 0.0e+00 0.4623759 0.321 0.074 0.0000003
FTL 0.0e+00 0.8599523 0.981 0.953 0.0000055
CAPG 0.0e+00 0.4751300 0.547 0.219 0.0000092
HLA-DMA 0.0e+00 0.3317938 0.453 0.149 0.0000126
NPC2 0.0e+00 0.4810930 0.566 0.239 0.0000236
HLA-DMB 0.0e+00 0.2830020 0.340 0.093 0.0000253
IGHM 0.0e+00 0.5623978 0.321 0.088 0.0000362
CST3 0.0e+00 0.5899121 0.491 0.204 0.0000621
STMN1 0.0e+00 0.3356627 0.321 0.091 0.0000767
TKT 0.0e+00 0.2536298 0.377 0.120 0.0001986
ASAH1 0.0e+00 0.2597505 0.377 0.123 0.0004828
CMTM6 2.0e-07 0.2544468 0.415 0.153 0.0027496
LGALS1 3.0e-07 0.5851548 0.566 0.295 0.0033734
HLA-DQB1 3.0e-07 0.4839694 0.491 0.238 0.0042709
ZFP36L1 9.0e-07 0.3381036 0.604 0.312 0.0112503
LYZ 1.4e-06 0.7266010 0.547 0.312 0.0172122
SAT1 2.2e-06 0.5650706 0.585 0.332 0.0272172
HLA-DRA 2.4e-06 0.8682362 0.679 0.567 0.0306470
FTH1 2.8e-06 0.6358502 0.981 0.977 0.0348959
GLUL 3.7e-06 0.3550762 0.340 0.131 0.0473811

We plot some of the intermediate monocyte marker genes. We can say with reasonable confidence that cluster 6 contains intermediate monocytes.

p58 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "LYZ") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p59 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "HLA-DRA") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p60 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "LST1") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p61 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "TYROBP") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
((p58 | p59) / (p60 | p61)) / p48

Visualization

We add final cell labels to our 8 cell clusters.

nkt_norm$label <- case_when(nkt_norm$seurat_clusters == 0 ~ "Memory CD4+ T", 
                            nkt_norm$seurat_clusters == 1 ~ "CD8+ T",
                            nkt_norm$seurat_clusters == 2 ~ "CD8+ T",
                            nkt_norm$seurat_clusters == 3 ~ "Naive CD4+ T",
                            nkt_norm$seurat_clusters == 4 ~ "NK",
                            nkt_norm$seurat_clusters == 5 ~ "T-reg", 
                            nkt_norm$seurat_clusters == 6 ~ "Intermediate Monocyte", 
                            nkt_norm$seurat_clusters == 7 ~ "Proliferating T-reg")
p62 <- DimPlot(nkt_norm, reduction = "tsne", group.by = "label") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p62

Ductal Cells

Reclustering

We use KRT8 expression to show the ductal cells residing in clusters 5 and 10. We note that some regions of clusters 5 and 10 have no KRT8 expression, which likely means that they are composed of different cell types.

p63 <- FeaturePlot(pdac, reduction = "tsne", features = "KRT8") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p63 / p4

We run SCISSORS, then use a Wilcoxon differential expression test to determine potential markers for each cluster.

ductal <- ReclusterCells(pdac, 
                         which.clust = list(5, 10), 
                         merge.clusters = TRUE, 
                         n.variable.genes = 4000, 
                         n.PC = 20, 
                         k.vals = c(10, 20, 30, 40), 
                         resolution.vals = c(.1, .2, .3, .4), 
                         which.dim.reduc = "tsne", 
                         redo.embedding = TRUE, 
                         do.plot = FALSE, 
                         random.seed = 629)
ductal_markers <- FindAllMarkers(ductal, 
                                 logfc.threshold = .5, 
                                 min.diff.pct = .2, 
                                 only.pos = TRUE, 
                                 verbose = FALSE, 
                                 random.seed = 629) %>% 
                  filter(p_val_adj < .05)
ductal_markers %>% 
  group_by(cluster) %>% 
  top_n(n = 3, wt = avg_logFC)
## [1] "Reclustering cells in cluster 5 using k = 20 & resolution = 0.1, which achieved silhouette score: 0.532"
p_val avg_logFC pct.1 pct.2 p_val_adj cluster gene
0 1.6982303 0.979 0.451 0 0 S100P
0 1.6562074 0.984 0.538 0 0 IFI27
0 1.3876187 0.731 0.234 0 0 TFF2
0 2.1429484 0.908 0.166 0 1 MMP7
0 2.2650786 0.844 0.260 0 1 CLU
0 3.4629760 0.866 0.389 0 1 SPP1
0 1.8261467 0.802 0.235 0 2 HLA-DPB1
0 1.6950322 0.740 0.204 0 2 HLA-DPA1
0 1.8014227 0.956 0.483 0 2 HLA-DRA
0 2.8948971 0.881 0.091 0 3 S100A2
0 2.3207514 0.435 0.010 0 3 CST1
0 2.0687281 0.701 0.112 0 3 PLAT
0 4.4278494 1.000 0.073 0 4 CELA3A
0 4.3544435 0.988 0.072 0 4 CTRB1
0 4.9087421 1.000 0.116 0 4 CTRB2
0 0.8412036 0.512 0.065 0 5 XIST
0 1.0563148 0.720 0.314 0 5 GPX2
0 0.7973432 0.787 0.499 0 5 LGALS4
0 2.6843866 0.718 0.019 0 6 CRISP3
0 2.6899477 0.846 0.103 0 6 TCN1
0 3.1343739 0.321 0.014 0 6 SCGB3A1
0 3.5917377 0.629 0.002 0 7 APOA4
0 3.8527263 0.671 0.007 0 7 APOA1
0 2.8721232 0.900 0.038 0 7 ALDOB

Again, we’ll run Fit-SNE on the reclustered cells.

duct_pc <- Embeddings(ductal, reduction = "pca")
# import data
duct_pc = r.duct_pc
# run Fit-SNE
affin_duct = PerplexityBasedNN(duct_pc, perplexity=200, metric='cosine', random_state=629)
init = initialization.pca(duct_pc, random_state=629)
tsne_duct = TSNEEmbedding(init, affin_duct, negative_gradient_method='fft')
embed_d1 = tsne_duct.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_d2 = embed_d1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
affin_duct.set_perplexity(30)
embed_d3 = embed_d2.optimize(n_iter=60, exaggeration=2, momentum=0.8)
embed_d4 = embed_d3.optimize(n_iter=500)

We pull the results into R, making sure to save the Barnes-Hut t-SNE results in another reduction slot.

embed_duct <- as.matrix(py$embed_d4)
rownames(embed_duct) <- colnames(ductal)
ductal@reductions$bh_tsne <- ductal@reductions$tsne
ductal@reductions$tsne<- CreateDimReducObject(embeddings = embed_duct, 
                                              key = "FitSNE_", 
                                              assay = "SCT", 
                                              global = TRUE)
p64 <- DimPlot(ductal, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p64

Cell Type Identification

Lipid Processing

We use ANPEP expression to identify the lipid processing ductal cells in cluster 7.

p65 <- FeaturePlot(ductal, reduction = "tsne", features = "ANPEP") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p65 / p64

Secretory

Expression of SOD3 and CFTR reveals the secretory cells in cluster 1.

p66 <- FeaturePlot(ductal, reduction = "tsne", features = "SOD3") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p67 <- FeaturePlot(ductal, reduction = "tsne", features = "CFTR") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p66 | p67) / p64

Classical 1

We use TFF1 and TFF2 expression to annotate the classical 1 epithelial cells in clusters 0 and 5. We can also see that the two classical 1 clusters are split by the sample from which the cells originate. Going forward, we’ll simply label both clusters as classical 1.

p68 <- FeaturePlot(ductal, reduction = "tsne", features = "TFF1") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p69 <- FeaturePlot(ductal, reduction = "tsne", features = "TFF2") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p70 <- DimPlot(ductal, reduction = "tsne", group.by = "sample") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Sample") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p68 | p70 | p69) / p64

Classical 2

The classical 2 cells are located in cluster 6, as evidenced by their expression of CRISP3.

p71 <- FeaturePlot(ductal, reduction = "tsne", features = "CRISP3") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p71 / p64

Basal-like

The basal compartment weights from DECODER are highest in cluster 3, which we will denote as being composed of basal-like PDAC.

p72 <- FeaturePlot(ductal, reduction = "tsne", features = "basal") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Basal-like") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p72 / p64

CD16+ Monocyte

As seen earlier in the results of the differential expression text, the top three genes for cluster 2 were HLA-DRA, HLA-DPA1, and HLA-DPB1. This points to cluster 2 being some kind of myeloid cell. We use expression of CD14, CD16 aka FCGR3A, and MS4A7 to identify it as containing CD14+ CD16+ monocytes.

p73 <- FeaturePlot(ductal, reduction = "tsne", features = "CD14") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p74 <- FeaturePlot(ductal, reduction = "tsne", features = "FCGR3A") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p75 <- FeaturePlot(ductal, reduction = "tsne", features = "MS4A7") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p73 | p74 | p75) / p64

All three genes are significantly differentially expressed in cluster 2.

clust2_markers <- FindMarkers(ductal, 
                              ident.1 = 2, 
                              random.seed = 629, 
                              only.pos = TRUE)
clust2_markers %>% 
  filter(rownames(clust2_markers) %in% c("CD14", "MS4A7", "FCGR3A")) %>% 
  arrange(desc(1 - p_val_adj))
p_val avg_logFC pct.1 pct.2 p_val_adj
MS4A7 0 0.9614771 0.485 0.014 0
CD14 0 1.2069216 0.551 0.061 0
FCGR3A 0 0.6200975 0.300 0.023 0

Acinar

Lastly, we show that cluster 4 is composed of acinar cells using CTRB2.

p76 <- FeaturePlot(ductal, reduction = "tsne", features = "CTRB2") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p76 / p64

Visualization

We add final cluster labels to our Seurat object and visualize the results.

ductal$label <- case_when(ductal$seurat_clusters == 0 ~ "Classical 1", 
                          ductal$seurat_clusters == 1 ~ "Secretory", 
                          ductal$seurat_clusters == 2 ~ "CD16+ Monocyte", 
                          ductal$seurat_clusters == 3 ~ "Basal-like", 
                          ductal$seurat_clusters == 4 ~ "Acinar", 
                          ductal$seurat_clusters == 5 ~ "Classical 1", 
                          ductal$seurat_clusters == 6 ~ "Classical 2", 
                          ductal$seurat_clusters == 7 ~ "Lipid proc.")
p77 <- DimPlot(ductal, reduction = "tsne", group.by = "label") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p77

Plasma Cells & Plasmacytoid DCs

We’ll run SCISSORS on cluster 11 in order to reveal its subgroups, the plasma cells and plasmacytoid DCs, as defined by their expression of IGJ (aka JCHAIN) and IRF7, respectively.

p78 <- FeaturePlot(pdac, reduction = "tsne", features = "JCHAIN") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "JCHAIN / IGJ") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p79 <- FeaturePlot(pdac, reduction = "tsne", features = "IRF7") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "IRF7") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p78 | p79) / p4

Reclustering

We run SCISSORS with default parameters.

plas <- ReclusterCells(pdac, 
                       which.clust = 11, 
                       n.PC = 20, 
                       which.dim.reduc = "tsne",
                       redo.embedding = TRUE, 
                       do.plot = FALSE, 
                       random.seed = 629)
plas_pc <- Embeddings(plas, reduction = "pca")
## [1] "Reclustering cells in cluster 11 using k = 25 & resolution = 0.1, which achieved silhouette score: 0.632"

Even though in this case it’s probably not necessary, we’ll run Fit-SNE on the cells just so that our axis labels are consistent.

# import data
plas_pc = r.plas_pc
# run Fit-SNE
affin_plas = PerplexityBasedNN(plas_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(plas_pc, random_state=629)
tsne_plas = TSNEEmbedding(init, affin_plas, negative_gradient_method='fft')
embed_p1 = tsne_plas.optimize(n_iter=250, exaggeration=12, momentum=0.6)
embed_p2 = embed_p1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
embed_plas <- as.matrix(py$embed_p2)
rownames(embed_plas) <- colnames(plas)
plas@reductions$bh_tsne <- plas@reductions$tsne
plas@reductions$tsne<- CreateDimReducObject(embeddings = embed_plas, 
                                            key = "FitSNE_", 
                                            assay = "SCT", 
                                            global = TRUE)
p80 <- DimPlot(plas, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p80

Cell Type Identification

We use the aforementioned markers to identify our two clusters.

p81 <- FeaturePlot(plas, reduction = "tsne", features = "JCHAIN") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "JCHAIN") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p82 <- FeaturePlot(plas, reduction = "tsne", features = "IRF7") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "IRF7") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p81 | p82) / p80

Visualization

As before, we add cell labels and visualize the results.

plas$label <- case_when(plas$seurat_clusters == 0 ~ "Plasma", 
                        plas$seurat_clusters == 1 ~ "pDC")
p83 <- DimPlot(plas, reduction = "tsne", group.by = "label") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p83

B Cells

We can identify the B cells in cluster 4 using joint expression of MS4A1 and CD79A. The cluster is split into two subclusters by tissue type: adjacent normal and PDAC. While it would be interesting to determine the genetic drivers of that separation, it’s somewhat outside of our scope here.

p84 <- FeaturePlot(pdac, reduction = "tsne", features = "MS4A1") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "MS4A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p85 <- FeaturePlot(pdac, reduction = "tsne", features = "CD79A") +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD79A") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p86 <- DimPlot(pdac, reduction = "tsne", group.by = "condition") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Tissue Type") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p84 | p86 | p85) / p4

Myeloid Cells

Lastly, we’ll split up the myeloid population by tissue condition (PDAC vs. adjacent normal) just like we did with the NK / T cells. We’ll run SCISSORS, annotate the clusters, and visualize the results.

Tumor

First we’ll attempt to assign broad cell type labels to each of the four putative myeloid clusters. We’ll use the marker genes from Elyada et al once again.

myo_tumor <- subset(pdac, subset = seurat_clusters %in% c(1, 2, 6, 9) & condition == "PDAC")
p87 <- DimPlot(myo_tumor, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p87

Cluster 1 appears to be composed of our resident macrophages due to its expression of CD14 and C1QA.

p88 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "CD14") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD14") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p89 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "C1QA") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "C1QA") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p88 | p89) / p87

We can use LYZ and S100A8 expression to reveal the classic monocytes and neutrophils in cluster 2.

p90 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "LYZ") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "LYZ") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p91 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "S100A8") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A8") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p90 | p91) / p87

Cluster 9 seems to house the alternatively activated macrophages, as shown by expression of SPP1.

p92 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "SPP1") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "SPP1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p92 / p87

Lastly, we show that cluster 6 contains our various DC subtypes through its expression of FCER1A, a canonical dendritic cell marker.

p93 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "FCER1A") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "FCER1A") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p93 / p87

Reclustering

Since we’ve already annotated some of the myeloid cell types, we’ll focus on cluster 2, which contains both monocytes and neutrophils, and the dendritic cells in cluster 6.

myo_reclust <- ReclusterCells(myo_tumor, 
                              which.clust = c(2, 6), 
                              n.PC = 10, 
                              merge.clusters = FALSE, 
                              k.vals = c(10, 20, 30, 40), 
                              resolution.vals = c(.2, .3, .4), 
                              n.variable.genes = 4000, 
                              which.dim.reduc = "tsne", 
                              redo.embedding = TRUE, 
                              do.plot = FALSE, 
                              random.seed = 629)
mono_tumor <- myo_reclust[[1]]
dc_tumor <- myo_reclust[[2]]
## [1] "Reclustering cells in cluster 2 using k = 40 & resolution = 0.2, which achieved silhouette score: 0.313"
## [1] "Reclustering cells in cluster 6 using k = 20 & resolution = 0.4, which achieved silhouette score: 0.454"

We’ll again run Fit-SNE on our reclustered cells.

mono_tumor_pc <- Embeddings(mono_tumor, "pca")
dc_tumor_pc <- Embeddings(dc_tumor, "pca")
# import data
mono_pc = r.mono_tumor_pc
dc_pc = r.dc_tumor_pc
# Fit-SNE - monocytes
affin_mono = PerplexityBasedNN(mono_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(mono_pc, random_state=629)
tsne_mono = TSNEEmbedding(init, affin_mono, negative_gradient_method='fft')
embed_mono1 = tsne_mono.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_mono2 = embed_mono1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
# Fit-SNE - DC
affin_dc = PerplexityBasedNN(dc_pc, perplexity=60, metric='cosine', random_state=629)
init = initialization.pca(dc_pc, random_state=629)
tsne_dc = TSNEEmbedding(init, affin_dc, negative_gradient_method='fft')
embed_dc1 = tsne_dc.optimize(n_iter=250, exaggeration=8, momentum=0.6)
embed_dc2 = embed_dc1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
affin_dc.set_perplexity(20)
embed_dc3 = embed_dc2.optimize(n_iter=100)

We pull the results back into R and visualize them.

embed_mono <- as.matrix(py$embed_mono2)
rownames(embed_mono) <- colnames(mono_tumor)
mono_tumor@reductions$bh_tsne <- mono_tumor@reductions$tsne
mono_tumor@reductions$tsne<- CreateDimReducObject(embeddings = embed_mono, 
                                                  key = "FitSNE_", 
                                                  assay = "SCT",
                                                  global = TRUE)
p94 <- DimPlot(mono_tumor, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p94

embed_dc <- as.matrix(py$embed_dc3)
rownames(embed_dc) <- colnames(dc_tumor)
dc_tumor@reductions$bh_tsne <- dc_tumor@reductions$tsne
dc_tumor@reductions$tsne<- CreateDimReducObject(embeddings = embed_dc, 
                                                key = "FitSNE_", 
                                                assay = "SCT",
                                                global = TRUE)
p95 <- DimPlot(dc_tumor, reduction = "tsne") + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p95

Cell Type Identification

Monoctyes & Neutrophils

First we ID the neutrophils in cluster 1 using S100A8 and S100A9 - marker genes used by Elyada et al.

p96 <- FeaturePlot(mono_tumor, reduction = "tsne", features = "S100A8") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A8") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p97 <- FeaturePlot(mono_tumor, reduction = "tsne", features = "S100A9") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A9") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p96 | p97) / p94

We can identify the classical monocytes in cluster 0 through expression of, you guessed it, CD14, as well as expression of CD16 aka FCGR3A.

p98 <- FeaturePlot(mono_tumor, reduction = "tsne", features = "CD14") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD14") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p99 <- FeaturePlot(mono_tumor, reduction = "tsne", features = "FCGR3A") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD16") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p98 | p99) / p94

We add cell labels to our Seurat object, then we’re off to the DCs.

mono_tumor$label <- case_when(mono_tumor$seurat_clusters == 0 ~ "Classical Monocyte", 
                              mono_tumor$seurat_clusters == 1 ~ "Neutrophil")
Dendritic Cells

We can use CLEC9A to annotate the cDC1 population in cluster 2.

p100 <- FeaturePlot(dc_tumor, reduction = "tsne", features = "CLEC9A") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CLEC9A") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p100 / p95

Joint expression of CD1A and CD207 reveals the Langerhans-like DCs in cluster 0.

p101 <- FeaturePlot(dc_tumor, reduction = "tsne", features = "CD1A") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD1A") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p102 <- FeaturePlot(dc_tumor, reduction = "tsne", features = "CD207") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD207") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p101 | p102) / p95

Next we use LAMP3 to identify the activated DCs in cluster 3.

p103 <- FeaturePlot(dc_tumor, reduction = "tsne", features = "LAMP3") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "LAMP3") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p103 / p95

Using a Wilcoxon differential expression test shows that cluster 1 is characterized by several conventionl DC2 marker genes / transcription factors.

dc_tumor_markers <- FindAllMarkers(dc_tumor, 
                                   logfc.threshold = .3, 
                                   only.pos = TRUE, 
                                   verbose = FALSE, 
                                   random.seed = 629)
dc_tumor_markers %>% 
  filter(p_val_adj < .05 & cluster == 1 & gene %in% c("CLEC10A", "KLF4", "ZEB2"))
p_val avg_logFC pct.1 pct.2 p_val_adj cluster gene
p104 <- FeaturePlot(dc_tumor, reduction = "tsne", features = "CLEC10A") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p105 <- FeaturePlot(dc_tumor, reduction = "tsne", features = "KLF4") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p106 <- FeaturePlot(dc_tumor, reduction = "tsne", features = "ZEB2") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p104 | p105 | p106) / p95

We add final subcluster cell type labels to our Seurat object, and then we’re off to the macrophages.

dc_tumor$label <- case_when(dc_tumor$seurat_clusters == 0 ~ "Langerhans-like DC", 
                            dc_tumor$seurat_clusters == 1 ~ "cDC2", 
                            dc_tumor$seurat_clusters == 2 ~ "cDC1", 
                            dc_tumor$seurat_clusters == 3 ~ "Activated DC")

Visualization

Monocytes & Neutrophils
p107 <- DimPlot(mono_tumor, reduction = "tsne", group.by = "label") + 
        scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p107

DCs
p108 <- DimPlot(dc_tumor, reduction = "tsne", group.by = "label") + 
        scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p108

Adjacent Normal

We have the same four clusters as in the tumor tissue: 1, 2, 6, and 9. We know that clusters 1 and 9 are composed of the resident and alternatively-activated macrophages, respectively. We’ll focus on the monocytes & neutrophils and DCs in clusters 2 and 6, respectively.

myo_norm <- subset(pdac, subset = seurat_clusters %in% c(1, 2, 6, 9) & condition == "AdjNorm")

Reclustering

myo_norm_reclust <- ReclusterCells(myo_norm, 
                                   which.clust = c(2, 6), 
                                   merge.clusters = FALSE, 
                                   n.variable.genes = 4000, 
                                   n.PC = 10, 
                                   which.dim.reduc = "tsne", 
                                   redo.embedding = TRUE, 
                                   random.seed = 629)
mono_norm <- myo_norm_reclust[[1]]
dc_norm <- myo_norm_reclust[[2]]
## [1] "Reclustering cells in cluster 2 using k = 25 & resolution = 0.1, which achieved silhouette score: 0.406"
## [1] "Reclustering cells in cluster 6 using k = 25 & resolution = 0.1, which achieved silhouette score: 0.48"

For the last time, we run Fit-SNE in order to obtain a better embedding.

mono_norm_pc <- Embeddings(mono_norm, "pca")
dc_norm_pc <- Embeddings(dc_norm, "pca")
# import data
mono_pc = r.mono_norm_pc
dc_pc = r.dc_norm_pc
# Fit-SNE - monocytes
affin_mono = PerplexityBasedNN(mono_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(mono_pc, random_state=629)
tsne_mono = TSNEEmbedding(init, affin_mono, negative_gradient_method='fft')
embed_mono1 = tsne_mono.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_mono2 = embed_mono1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
# Fit-SNE - DC
affin_dc = PerplexityBasedNN(dc_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(dc_pc, random_state=629)
tsne_dc = TSNEEmbedding(init, affin_dc, negative_gradient_method='fft')
embed_dc1 = tsne_dc.optimize(n_iter=250, exaggeration=8, momentum=0.6)
embed_dc2 = embed_dc1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

We pull the results back into R and visualize them.

embed_mono <- as.matrix(py$embed_mono2)
rownames(embed_mono) <- colnames(mono_norm)
mono_norm@reductions$bh_tsne <- mono_norm@reductions$tsne
mono_norm@reductions$tsne<- CreateDimReducObject(embeddings = embed_mono, 
                                                 key = "FitSNE_", 
                                                 assay = "SCT",
                                                 global = TRUE)
p109 <- DimPlot(mono_norm, reduction = "tsne") + 
        scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p109

embed_dc <- as.matrix(py$embed_dc2)
rownames(embed_dc) <- colnames(dc_norm)
dc_norm@reductions$bh_tsne <- dc_norm@reductions$tsne
dc_norm@reductions$tsne<- CreateDimReducObject(embeddings = embed_dc, 
                                               key = "FitSNE_", 
                                               assay = "SCT",
                                               global = TRUE)
p110 <- DimPlot(dc_norm, reduction = "tsne") + 
        scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p110

Cell Type Identification

Monocytes & Neutrophils

We use high S100A8 and S100A9 expression to define the neutrophils in cluster 2.

p111 <- FeaturePlot(mono_norm, reduction = "tsne", features = "S100A8") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p112 <- FeaturePlot(mono_norm, reduction = "tsne", features = "S100A9") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p111 | p112) / p109

Next up are the classical monocytes in clusters 0 and 1, split by sample.

p113 <- FeaturePlot(mono_norm, reduction = "tsne", features = "CD68") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p114 <- FeaturePlot(mono_norm, reduction = "tsne", features = "CD14") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p115 <- DimPlot(mono_norm, reduction = "tsne", group.by = "sample") + 
        scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Sample") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p113 | p115 | p114) / p109

Lastly, it seems we have a small group of CD8+ T cells in cluster 3 that snuck into the myeloid cluster, as defined by their expression of CD2, CD3D (marking them as NK / T cells), and CD8A & NKG7. I don’t believe they’re NK cells as the do not express PRF1 or GZMB.

p116 <- FeaturePlot(mono_norm, reduction = "tsne", features = "CD2") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p117 <- FeaturePlot(mono_norm, reduction = "tsne", features = "CD3D") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p118 <- FeaturePlot(mono_norm, reduction = "tsne", features = "CD8A") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p119 <- FeaturePlot(mono_norm, reduction = "tsne", features = "NKG7") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
((p116 | p117) / (p118 | p119)) / p109

We add labels to our clusters.

mono_norm$label <- case_when(mono_norm$seurat_clusters == 0 ~ "Classic Monocyte", 
                             mono_norm$seurat_clusters == 1 ~ "Classic Monocyte", 
                             mono_norm$seurat_clusters == 2 ~ "Neutrophil", 
                             mono_norm$seurat_clusters == 3 ~ "CD8+ T")
Dendritic Cells

We annotate cluster 1 as conventional DC1 and cluster 0 as conventional DC2 through mutually exclusive expression of the canonical markers CLEC9A and CLEC10A, respectively.

p120 <- FeaturePlot(dc_norm, reduction = "tsne", features = "CLEC9A") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p121 <- FeaturePlot(dc_norm, reduction = "tsne", features = "CLEC10A") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p120 | p121) / p110

Labels are added to our adjacent normal tissue DC Seurat object.

dc_norm$label <- case_when(dc_norm$seurat_clusters == 0 ~ "cDC2", 
                           dc_norm$seurat_clusters == 1 ~ "cDC1")

Visualization

Here are the final annotations for the adjacent normal tissue myeloid population.

p122 <- DimPlot(mono_norm, reduction = "tsne", group.by = "label") + 
        scale_color_manual(values = paletteer_d("awtools::mpalette")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p122

p123 <- DimPlot(dc_norm, reduction = "tsne", group.by = "label") + 
        scale_color_manual(values = paletteer_d("awtools::mpalette")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 3)))
p123

Conclusions

Save Figures & Data

We’ll create a quick convenience function to help us save the figures.

saveSCISSORS <- function(plot = NULL, 
                         name = NULL, 
                         border = TRUE, 
                         pub.ready = FALSE) {
  if (is.null(plot) | is.null(name)) stop("You forgot some arguments.")
  if (pub.ready) {
    dir <- "~/Desktop/R/SCISSORS/vignettes/figures_pub/Elyada/"
    if (!border) {
      plot <- plot + 
              theme(panel.border = element_blank(), 
                    axis.title = element_blank(), 
                    legend.position = "none")
    } else {
      plot <- plot + 
              theme(axis.title = element_blank(), 
                    legend.position = "none")
    }
    ggsave(filename = paste0(name, ".pdf"), 
           device = "pdf", 
           units = "in",
           path = dir, 
           height = 5, 
           width = 5) 
  } else {
    dir <- "~/Desktop/R/SCISSORS/vignettes/figures_supp/Elyada/"
    ggsave(filename = paste0(name, ".pdf"), 
           device = "pdf", 
           units = "in",
           path = dir, 
           height = 5, 
           width = 5) 
  }
}

This section isn’t worth reading; it’s here solely to prove that the figures we present in our publication were dynamically generated during the knitting of this document.

saveSCISSORS(plot = p0, name = "Seurat_Clusters_tSNE.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p1, name = "Seurat_Clusters_UMAP.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p4, name = "Seurat_Clusters_FitSNE.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p5, name = "SingleR_Annos_sc_ref.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p6, name = "SingleR_Annos_bulk_ref.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p7, name = "CONICSmat_Annos.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p8, name = "DECODER_basal.pdf")
saveSCISSORS(plot = p9, name = "DECODER_classical.pdf")
saveSCISSORS(plot = p10, name = "DECODER_exocrine.pdf")
saveSCISSORS(plot = p11, name = "DECODER_endocrine.pdf")
saveSCISSORS(plot = p12, name = "DECODER_immune.pdf")
saveSCISSORS(plot = p13, name = "DECODER_normal_stroma.pdf")
saveSCISSORS(plot = p14, name = "DECODER_act_stroma.pdf")
saveSCISSORS(plot = p15, name = "Fibro_all_cells_COL1A1.pdf")
saveSCISSORS(plot = p16, name = "Fibro_all_cells_COL3A1.pdf")
saveSCISSORS(plot = p17, name = "Fibro_all_cells_LUM.pdf")
saveSCISSORS(plot = p18, name = "Fibro_all_cells_DCN.pdf")
saveSCISSORS(plot = p19, name = "Fibro_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p20, name = "Fibro_iCAF_VAM.pdf")
saveSCISSORS(plot = p21, name = "Fibro_myCAF_VAM.pdf")
saveSCISSORS(plot = p22, name = "Fibro_apCAF_VAM.pdf")
saveSCISSORS(plot = p23, name = "Fibro_final_labels.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p24, name = "Endo_Perivascular_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p25, name = "Perivascular_IGFBP7.pdf")
saveSCISSORS(plot = p26, name = "Perivascular_ACTA2.pdf")
saveSCISSORS(plot = p27, name = "Perivascular_RGS5.pdf")
saveSCISSORS(plot = p28, name = "Endothelial_PLVAP.pdf")
saveSCISSORS(plot = p29, name = "Endothelial_VWF.pdf")
saveSCISSORS(plot = p30, name = "Endo_Perivascular_final_labels.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p31, name = "NKT_all_cells_CD3D.pdf")
saveSCISSORS(plot = p32, name = "NKT_Tumor_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p33, name = "NKT_Tumor_CD4T_IL7R.pdf")
saveSCISSORS(plot = p34, name = "NKT_Tumor_CD4T_CD69.pdf")
saveSCISSORS(plot = p35, name = "NKT_Tumor_Treg_IL2RA.pdf")
saveSCISSORS(plot = p36, name = "NKT_Tumor_Treg_FOXP3.pdf")
saveSCISSORS(plot = p37, name = "NKT_Tumor_Prolif_Treg_TOP2A.pdf")
saveSCISSORS(plot = p38, name = "NKT_Tumor_Mast_TPSAB1.pdf")
saveSCISSORS(plot = p39, name = "NKT_Tumor_NK_NKG7.pdf")
saveSCISSORS(plot = p40, name = "NKT_Tumor_NK_PRF1.pdf")
saveSCISSORS(plot = p41, name = "NKT_Tumor_CD8T_CD8A.pdf")
saveSCISSORS(plot = p42, name = "NKT_Tumor_CD8T_CD2.pdf")
saveSCISSORS(plot = p43, name = "NKT_Tumor_Intermediate_Mono_LYZ.pdf")
saveSCISSORS(plot = p44, name = "NKT_Tumor_Intermediate_Mono_HLADRA.pdf")
saveSCISSORS(plot = p45, name = "NKT_Tumor_Intermediate_Mono_CD74.pdf")
saveSCISSORS(plot = p46, name = "NKT_Tumor_Intermediate_Mono_HLADPB1.pdf")
saveSCISSORS(plot = p47, name = "NKT_Tumor_final_labels.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p48, name = "NKT_Norm_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p49, name = "NKT_Norm_CD4T_IL7R.pdf")
saveSCISSORS(plot = p50, name = "NKT_Norm_CD4T_S100A4.pdf")
saveSCISSORS(plot = p51, name = "NKT_Norm_CD4T_CCR7.pdf")
saveSCISSORS(plot = p52, name = "NKT_Norm_CD8T_CD8A.pdf")
saveSCISSORS(plot = p53, name = "NKT_Norm_Treg_TIGIT.pdf")
saveSCISSORS(plot = p54, name = "NKT_Norm_Treg_FOXP3.pdf")
saveSCISSORS(plot = p55, name = "NKT_Norm_NK_PRF1.pdf")
saveSCISSORS(plot = p56, name = "NKT_Norm_NK_NKG7.pdf")
saveSCISSORS(plot = p57, name = "NKT_Norm_Prolif_Treg_TOP2A.pdf")
saveSCISSORS(plot = p58, name = "NKT_Norm_Intermediate_Mono_LYZ.pdf")
saveSCISSORS(plot = p59, name = "NKT_Norm_Intermediate_Mono_HLADRA.pdf")
saveSCISSORS(plot = p60, name = "NKT_Norm_Intermediate_Mono_LST1.pdf")
saveSCISSORS(plot = p61, name = "NKT_Norm_Intermediate_Mono_TYROBP.pdf")
saveSCISSORS(plot = p62, name = "NKT_Norm_SCISSORS_FitSNE.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p63, name = "Ductal_all_cells_KRT8.pdf")
saveSCISSORS(plot = p64, name = "Ductal_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p65, name = "Ductal_Lipid_Proc_ANPEP.pdf")
saveSCISSORS(plot = p66, name = "Ductal_Secretory_SOD3.pdf")
saveSCISSORS(plot = p67, name = "Ductal_Secretory_CFTR.pdf")
saveSCISSORS(plot = p68, name = "Ductal_Classical1_TFF1.pdf")
saveSCISSORS(plot = p69, name = "Ductal_Classical1_TFF2.pdf")
saveSCISSORS(plot = p70, name = "Ductal_Classical1_SampleID.pdf")
saveSCISSORS(plot = p71, name = "Ductal_Classical2_CRISP3.pdf")
saveSCISSORS(plot = p72, name = "Ductal_basal_DECODER.pdf")
saveSCISSORS(plot = p73, name = "Ductal_CD16_Mono_CD14.pdf")
saveSCISSORS(plot = p74, name = "Ductal_CD16_Mono_FCGR3A.pdf")
saveSCISSORS(plot = p75, name = "Ductal_CD16_Mono_MS4A7.pdf")
saveSCISSORS(plot = p76, name = "Ductal_Acinar_CTRB2.pdf")
saveSCISSORS(plot = p77, name = "Ductal_final_labels.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p78, name = "Plasma_all_cells_IGJ.pdf")
saveSCISSORS(plot = p79, name = "Plasma_all_cells_IRF7.pdf")
saveSCISSORS(plot = p80, name = "Plasma_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p81, name = "Plasma_Plasma_JCHAIN.pdf")
saveSCISSORS(plot = p82, name = "Plasma_pDC_IGJ.pdf")
saveSCISSORS(plot = p83, name = "Plasma_final_labels.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p84, name = "B_all_cells_MS4A1.pdf")
saveSCISSORS(plot = p85, name = "B_all_cells_CD79A.pdf")
saveSCISSORS(plot = p86, name = "B_all_cells_tissue_type.pdf")
saveSCISSORS(plot = p87, name = "Myeloid_Tumor_original_FitSNE.pdf")
saveSCISSORS(plot = p88, name = "Myeloid_Tumor_Resident_Macro_CD14.pdf")
saveSCISSORS(plot = p89, name = "Myeloid_Tumor_Resident_Macro_C1QA.pdf")
saveSCISSORS(plot = p90, name = "Myeloid_Tumor_Classic_Mono_LYZ.pdf")
saveSCISSORS(plot = p91, name = "Myeloid_Tumor_Classic_Mono_S100A8.pdf")
saveSCISSORS(plot = p92, name = "Myeloid_Tumor_Alternative_Macro_Spp1.pdf")
saveSCISSORS(plot = p93, name = "Myeloid_Tumor_DC_FCER1A.pdf")
saveSCISSORS(plot = p94, name = "Monocyte_Tumor_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p95, name = "DC_Tumor_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p96, name = "Monocyte_Tumor_Neutrophil_S100A8.pdf")
saveSCISSORS(plot = p97, name = "Monocyte_Tumor_Neutrophil_S100A9.pdf")
saveSCISSORS(plot = p98, name = "Monocyte_Tumor_Classic_Mono_CD14.pdf")
saveSCISSORS(plot = p99, name = "Monocyte_Tumor_Classic_Mono_FCGR3A.pdf")
saveSCISSORS(plot = p100, name = "DC_Tumor_cDC1_CLEC9A.pdf")
saveSCISSORS(plot = p101, name = "DC_Tumor_Langerhans_DC_CD1A.pdf")
saveSCISSORS(plot = p102, name = "DC_Tumor_Langerhans_DC_CD207.pdf")
saveSCISSORS(plot = p103, name = "DC_Tumor_Activated_DC_LAMP3.pdf")
saveSCISSORS(plot = p104, name = "DC_Tumor_cDC2_CLEC10A.pdf")
saveSCISSORS(plot = p105, name = "DC_Tumor_cDC2_KLF4.pdf")
saveSCISSORS(plot = p106, name = "DC_Tumor_cDC2_ZEB2.pdf")
saveSCISSORS(plot = p107, name = "Mono_Tumor_final_labels.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p108, name = "DC_Tumor_final_labels.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p109, name = "Mono_Norm_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p110, name = "DC_Norm_SCISSORS_FitSNE.pdf")
saveSCISSORS(plot = p111, name = "Mono_Norm_Neutrophil_S100A8.pdf")
saveSCISSORS(plot = p112, name = "Mono_Norm_Neutrophil_S100A9.pdf")
saveSCISSORS(plot = p113, name = "Mono_Norm_Classic_Monocyte_CD68.pdf")
saveSCISSORS(plot = p114, name = "Mono_Norm_Classic_Monocyte_CD14.pdf")
saveSCISSORS(plot = p115, name = "Mono_Norm_Classic_MOnocyte_SampleID.pdf")
saveSCISSORS(plot = p116, name = "Mono_Norm_CD8T_CD2.pdf")
saveSCISSORS(plot = p117, name = "Mono_Norm_CD8T_CD3D.pdf")
saveSCISSORS(plot = p118, name = "Mono_Norm_CD8T_CD8A.pdf")
saveSCISSORS(plot = p119, name = "Mono_Norm_CD8T_NKG7.pdf")
saveSCISSORS(plot = p120, name = "DC_Norm_cDC1_CLEC9A.pdf")
saveSCISSORS(plot = p121, name = "DC_Norm_cDC2_CLEC10A.pdf")
saveSCISSORS(plot = p122, name = "Mono_Norm_final_labels.pdf", pub.ready = TRUE, border = FALSE)
saveSCISSORS(plot = p123, name = "DC_Norm_final_labels.pdf", pub.ready = TRUE, border = FALSE)

And of course:

sessionInfo()
## R version 4.0.3 (2020-10-10)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Catalina 10.15.7
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] parallel  stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] wesanderson_0.3.6.9000      reticulate_1.18            
##  [3] CONICSmat_0.0.0.1           paletteer_1.3.0            
##  [5] patchwork_1.1.1             mixtools_1.2.0             
##  [7] SCISSORS_0.0.2.0            SingleCellExperiment_1.12.0
##  [9] data.table_1.13.6           cluster_2.1.0              
## [11] biomaRt_2.44.1              decoderr_0.0.0.9000        
## [13] SingleR_1.2.4               SummarizedExperiment_1.20.0
## [15] Biobase_2.50.0              GenomicRanges_1.42.0       
## [17] GenomeInfoDb_1.26.2         IRanges_2.24.1             
## [19] S4Vectors_0.28.1            BiocGenerics_0.36.0        
## [21] MatrixGenerics_1.2.0        matrixStats_0.57.0         
## [23] ggplot2_3.3.3               dplyr_1.0.2                
## [25] VAM_0.4.0                   MASS_7.3-53                
## [27] Seurat_3.2.3                pals_1.6                   
## 
## loaded via a namespace (and not attached):
##   [1] tidyselect_1.1.0              RSQLite_2.2.2                
##   [3] AnnotationDbi_1.50.3          htmlwidgets_1.5.3            
##   [5] grid_4.0.3                    BiocParallel_1.22.0          
##   [7] Rtsne_0.15                    munsell_0.5.0                
##   [9] codetools_0.2-18              ica_1.0-2                    
##  [11] statmod_1.4.35                scran_1.16.0                 
##  [13] future_1.21.0                 miniUI_0.1.1.1               
##  [15] withr_2.3.0                   colorspace_2.0-0             
##  [17] highr_0.8                     knitr_1.30                   
##  [19] ROCR_1.0-11                   tensor_1.5                   
##  [21] listenv_0.8.0                 labeling_0.4.2               
##  [23] GenomeInfoDbData_1.2.4        polyclip_1.10-0              
##  [25] pheatmap_1.0.12               bit64_4.0.5                  
##  [27] farver_2.0.3                  parallelly_1.23.0            
##  [29] vctrs_0.3.6                   generics_0.1.0               
##  [31] xfun_0.20                     BiocFileCache_1.12.1         
##  [33] squash_1.0.9                  R6_2.5.0                     
##  [35] ggbeeswarm_0.6.0              rsvd_1.0.3                   
##  [37] locfit_1.5-9.4                bitops_1.0-6                 
##  [39] spatstat.utils_1.20-2         DelayedArray_0.16.0          
##  [41] assertthat_0.2.1              promises_1.1.1               
##  [43] scales_1.1.1                  beeswarm_0.2.3               
##  [45] gtable_0.3.0                  globals_0.14.0               
##  [47] goftest_1.2-2                 rlang_0.4.10                 
##  [49] splines_4.0.3                 lazyeval_0.2.2               
##  [51] dichromat_2.0-0               prismatic_1.0.0              
##  [53] BiocManager_1.30.10           yaml_2.2.1                   
##  [55] reshape2_1.4.4                abind_1.4-5                  
##  [57] httpuv_1.5.4                  tools_4.0.3                  
##  [59] ellipsis_0.3.1                RColorBrewer_1.1-2           
##  [61] ggridges_0.5.3                Rcpp_1.0.5                   
##  [63] plyr_1.8.6                    progress_1.2.2               
##  [65] zlibbioc_1.36.0               purrr_0.3.4                  
##  [67] RCurl_1.98-1.2                prettyunits_1.1.1            
##  [69] rpart_4.1-15                  openssl_1.4.3                
##  [71] deldir_0.2-3                  viridis_0.5.1                
##  [73] pbapply_1.4-3                 cowplot_1.1.1                
##  [75] zoo_1.8-8                     ggrepel_0.9.0                
##  [77] magrittr_2.0.1                RSpectra_0.16-0              
##  [79] scattermore_0.7               lmtest_0.9-38                
##  [81] RANN_2.6.1                    fitdistrplus_1.1-3           
##  [83] hms_0.5.3                     mime_0.9                     
##  [85] evaluate_0.14                 xtable_1.8-4                 
##  [87] XML_3.99-0.5                  gridExtra_2.3                
##  [89] scater_1.16.2                 compiler_4.0.3               
##  [91] tibble_3.0.4                  maps_3.3.0                   
##  [93] KernSmooth_2.23-18            crayon_1.3.4                 
##  [95] htmltools_0.5.0               segmented_1.3-1              
##  [97] mgcv_1.8-33                   later_1.1.0.1                
##  [99] tidyr_1.1.2                   DBI_1.1.0                    
## [101] ExperimentHub_1.14.2          dbplyr_2.0.0                 
## [103] rappdirs_0.3.1                Matrix_1.3-2                 
## [105] igraph_1.2.6                  pkgconfig_2.0.3              
## [107] plotly_4.9.3                  vipor_0.4.5                  
## [109] dqrng_0.2.1                   XVector_0.30.0               
## [111] stringr_1.4.0                 digest_0.6.27                
## [113] sctransform_0.3.2             RcppAnnoy_0.0.18             
## [115] spatstat.data_1.7-0           rmarkdown_2.6                
## [117] leiden_0.3.6                  uwot_0.1.10                  
## [119] edgeR_3.30.3                  DelayedMatrixStats_1.10.1    
## [121] curl_4.3                      kernlab_0.9-29               
## [123] shiny_1.5.0                   lifecycle_0.2.0              
## [125] nlme_3.1-151                  jsonlite_1.7.2               
## [127] BiocNeighbors_1.6.0           mapproj_1.2.7                
## [129] viridisLite_0.3.0             askpass_1.1                  
## [131] limma_3.44.3                  pillar_1.4.7                 
## [133] lattice_0.20-41               fastmap_1.0.1                
## [135] httr_1.4.2                    survival_3.2-7               
## [137] interactiveDisplayBase_1.26.3 glue_1.4.2                   
## [139] spatstat_1.64-1               png_0.1-7                    
## [141] BiocVersion_3.11.1            bit_4.0.4                    
## [143] nnls_1.4                      stringi_1.5.3                
## [145] rematch2_2.1.2                blob_1.2.1                   
## [147] BiocSingular_1.4.0            AnnotationHub_2.20.2         
## [149] memoise_1.1.0                 irlba_2.3.3                  
## [151] future.apply_1.7.0
LS0tCnRpdGxlOiAiUmVjbHVzdGVyaW5nIEFuYWx5c2lzIG9mIENhbmNlci1Bc3NvY2lhdGVkIEZpYnJvYmxhc3QgVXNpbmcgU0NJU1NPUlMiCnN1YnRpdGxlOiAiSmFjayBMZWFyeSIKYXV0aG9yOiAKICAtICJVbml2ZXJzaXR5IG9mIE5vcnRoIENhcm9saW5hIGF0IENoYXBlbCBIaWxsIC0gTGluZWJlcmdlciBDb21wcmVoZW5zaXZlIENhbmNlciBDZW50ZXIiCiAgLSAiVW5pdmVyc2l0eSBvZiBGbG9yaWRhIC0gRGVwYXJ0bWVudCBvZiBCaW9zdGF0aXN0aWNzIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHBhcGVyCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBkZl9wcmludDoga2FibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9ICJob2xkIiwgCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIikKcmV0aWN1bGF0ZTo6dXNlX3ZpcnR1YWxlbnYoIn4vRGVza3RvcC9QeXRob24vc2NpZW5jZS92ZW52LyIsIHJlcXVpcmVkID0gVFJVRSkKc2V0LnNlZWQoNjI5KQpgYGAKCiMgSW50cm9kdWN0aW9uCgpJbiAyMDE3LCB0aGUgVHV2ZXNvbiBMYWIgYXQgQ29sZCBTcHJpbmcgSGFyYm9yIENhbmNlciBDZW50ZXIgcHVibGlzaGVkIGEgcGFwZXIgd3JpdHRlbiBieSBFbHlhZGEgKmV0IGFsKiAoMjAxNykgdGhhdCBkZXRhaWxlZCB0aGUgZGlzY292ZXJ5IG9mIGNhbmNlci1hc3NvY2lhdGVkIGZpYnJvYmxhc3RzIChDQUZzKSBpbiBtaWNlLiBUaGUgc3VidHlwZXMgd2VyZSB0aGVuIHZhbGlkYXRlZCBpbiBodW1hbiBzYW1wbGVzIGFmZmVjdGVkIHdpdGggUERBQyBpbiBhIHN1YnNlcXVlbnQgcGFwZXIgcmVsZWFzZWQgaW4gMjAxOS4gSGVyZSB3ZSB3aWxsIHVzZSBTQ0lTU09SUyB0byBpZGVudGlmeSB0aGUgQ0FGIHN1YnR5cGVzIHdpdGhpbiB0aGUgbGFyZ2VyIGZpYnJvYmxhc3QgcG9wdWxhdGlvbiwgaW1tdW5lIGNlbGwgdHlwZXMgd2l0aGluIGJyb2FkbHktZGVmaW5lZCBpbW11bmUgY2x1c3RlcnMsIGFuZCBkdWN0YWwgJiBQREFDIHN1YnR5cGVzIHdpdGhpbiB0aGUgZHVjdGFsIGdyb3VwLiAKCiMgTGlicmFyaWVzCgojIyBSCgpgYGB7cn0KbGlicmFyeShwYWxzKSAgICAgICAgIyBoaWdoIE4gZGlzY3JldGUgY29sb3IgcGFsZXR0ZXMKbGlicmFyeShWQU0pICAgICAgICAgIyBzaW5nbGUgY2VsbCBHU0VBCmxpYnJhcnkoZHBseXIpICAgICAgICMgdGlkeSBkYXRhIApsaWJyYXJ5KFNldXJhdCkgICAgICAjIHNpbmdsZSBjZWxsIGluZnJhc3RydWN0dXJlCmxpYnJhcnkoZ2dwbG90MikgICAgICMgcGxvdHMKbGlicmFyeShTaW5nbGVSKSAgICAgIyBjZWxsIHR5cGUgYXNzaWdubWVudApsaWJyYXJ5KGRlY29kZXJyKSAgICAjIGRlIG5vdm8gZGVjb252b2x1dGlvbiAKbGlicmFyeShTQ0lTU09SUykgICAgIyBvdXIgcGFja2FnZQpsaWJyYXJ5KG1peHRvb2xzKSAgICAjIEdhdXNzaWFuIG1peHR1cmUgbW9kZWwgZXN0aW1hdGlvbgpsaWJyYXJ5KHBhdGNod29yaykgICAjIHBsb3QgZ3JpZHMKbGlicmFyeShwYWxldHRlZXIpICAgIyBtb3JlIGNvbG9yIHBhbGV0dGVzCmxpYnJhcnkoQ09OSUNTbWF0KSAgICMgQ05WIGVzdGltYXRpb24KbGlicmFyeShyZXRpY3VsYXRlKSAgIyBQeXRob24gaW50ZXJmYWNlCmxpYnJhcnkod2VzYW5kZXJzb24pICMgZXZlbiBtb3JlIGNvbG9yIHBhbGV0dGVzCmBgYAoKIyMgUHl0aG9uCgpgYGB7cHl0aG9ufQppbXBvcnQgbnVtcHkgYXMgbnAKZnJvbSBvcGVuVFNORSBpbXBvcnQgVFNORUVtYmVkZGluZwpmcm9tIG9wZW5UU05FIGltcG9ydCBpbml0aWFsaXphdGlvbgpmcm9tIG9wZW5UU05FLmFmZmluaXR5IGltcG9ydCBNdWx0aXNjYWxlCmZyb20gb3BlblRTTkUuYWZmaW5pdHkgaW1wb3J0IFBlcnBsZXhpdHlCYXNlZE5OCmBgYAoKIyBEYXRhCgpGaXJzdCB3ZSBsb2FkIGluIHRoZSAkXHRleHR7Z2VuZX0gXHRpbWVzIFx0ZXh0e2NlbGx9JCBjb3VudHMgbWF0cml4LCB0aGVuIGNyZWF0ZSBhIGBTZXVyYXRgIG9iamVjdCB0byBob2xkIGl0IGluLiBOZXh0LCB3ZSBhZGQgc2FtcGxlbmFtZSwgdGlzc3VlIHR5cGUsIGFuZCBwYXRpZW50IHNleCBtZXRhZGF0YSB0YWtlbiBmcm9tIHRoZSBwdWJsaWNseSBhdmFpbGFibGUgZGF0YXNldC4KCmBgYHtyfQpyYXdfY291bnRzIDwtIFJlYWQxMFgoZGF0YS5kaXIgPSAifi9EZXNrdG9wL0RhdGEvRWx5YWRhIFJhdy9BbGwgSHVtYW4vIikKcGRhYyA8LSBDcmVhdGVTZXVyYXRPYmplY3QocmF3X2NvdW50cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2plY3QgPSAiRWx5YWRhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5jZWxscyA9IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZmVhdHVyZXMgPSA1MDApCnBkYWNAbWV0YS5kYXRhJHNhbXBsZSA8LSBjYXNlX3doZW4oZ3JlcGwoIi0xIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJTUlI5Mjc0NTM2IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi0yIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJTUlI5Mjc0NTM3IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi0zIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJTUlI5Mjc0NTM4IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi00Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJTUlI5Mjc0NTM5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTUiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTYiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTciLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTgiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTkiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1NDQiKQpwZGFjQG1ldGEuZGF0YSRjb25kaXRpb24gPC0gY2FzZV93aGVuKGdyZXBsKCItMSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItMiIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItMyIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNCIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNiIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiQWRqTm9ybSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNyIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItOCIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiQWRqTm9ybSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItOSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiUERBQyIpCnBkYWNAbWV0YS5kYXRhJHNleCA8LSBjYXNlX3doZW4oZ3JlcGwoIi0xIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJmZW1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTIiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTMiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTQiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTUiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTYiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gImZlbWFsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNyIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiZmVtYWxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi04Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJtYWxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi05Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJmZW1hbGUiKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpybShyYXdfY291bnRzKQpgYGAKCiMgUHJlcHJvY2Vzc2luZwoKV2UgcnVuIHRoZSB0eXBpY2FsIHNpbmdsZSBjZWxsIHByZS1wcm9jZXNzaW5nIHN0ZXBzIG9uIG91ciBjZWxscyAtIG5vcm1hbGl6YXRpb24sIGRpbWVuc2lvbiByZWR1Y3Rpb24sIGFuZCBjbHVzdGVyaW5nLiBUaGUgdC1TTkUgZW1iZWRkaW5nIGxvb2tzIGRlY2VudCwgYnV0IGNvdWxkIGRlZmluaXRlbHkgYmUgaW1wcm92ZWQuIEdsb2JhbGx5LCB0aGUgY2x1c3RlcnMgYXJlIGFycmFuZ2VkIGluIGEgYmxvYiAtIHdoaWNoIGlzbid0IHZlcnkgaW5mb3JtYXRpdmUgLSB0aG91Z2ggdGhlIGxvY2FsIHN0cnVjdHVyZSBzZWVtcyB0byBoYXZlIGJlZW4gcHJlc2VydmVkIGZhaXJseSB3ZWxsLiBDbHVzdGVycyA1IGFuZCAxMSBhcmUgc3BsaXQgaW4gdHdvLCB3aGljaCB3ZSB3b3VsZCBwcmVmZXIgbm90IHRvIGhhdmUgaGFwcGVuLiAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpwZGFjIDwtIFByZXBhcmVEYXRhKHBkYWMsIAogICAgICAgICAgICAgICAgICAgIG4udmFyaWFibGUuZ2VuZXMgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICBuLlBDID0gMjAsIAogICAgICAgICAgICAgICAgICAgIHdoaWNoLmRpbS5yZWR1YyA9ICJ0c25lIiwgCiAgICAgICAgICAgICAgICAgICAgaW5pdGlhbC5yZXNvbHV0aW9uID0gLjUsIAogICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQpwMCA8LSBEaW1QbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIikgKyAKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHVubmFtZSh0YWJsZWF1MjAoKSkpICsgCiAgICAgIGxhYnMoeCA9ICJ0LVNORSAxIiwgeSA9ICJ0LVNORSAyIikgKyAKICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnAwCmBgYAoKIyMgT3B0aW1pemUgRGltZW5zaW9uIFJlZHVjdGlvbgoKSSB0aGluayB0aGUgdHdvLWRpbWVuc2lvbmFsIHZpc3VhbGl6YXRpb24gb2YgdGhlIGNlbGxzIGNvdWxkIGJlIGltcHJvdmVkLiBXZSdsbCB0cnkgdXNpbmcgVU1BUCBhbmQgdGhlIEZhc3QgRm91cmllciBUcmFuc2Zvcm0tYWNjZWxlcmF0ZWQgRml0LVNORSAoYXMgaW1wbGVtZW50ZWQgaW4gdGhlIGBvcGVuVFNORWAgbGlicmFyeSkgdG8gaW1wcm92ZSB0aGUgZW1iZWRkaW5nLgoKIyMjIFVNQVAKCkl0IHNlZW1zIGxpa2UgVU1BUCBkb2VzIGEgZ29vZCBqb2Igb2YgY2xlYXJseSBzZXBhcmF0aW5nIG91ciBjbHVzdGVycyBhbmQgcHJlc2VydmluZyB0aGUgZ2xvYmFsIHN0cnVjdHVyZSBvZiB0aGUgZGF0YS4gSG93ZXZlciwgIGRpZmZpY3VsdCB0byBzZWUgbG9jYWwgc3RydWN0dXJlIHdpdGhpbiBzb21lIG9mIHRoZSBjbHVzdGVycyBkdWUgdG8gdGhlaXIgZGVuc2l0eSwgYW5kIGNsdXN0ZXIgNSBpcyBzcGxpdCBhY3Jvc3MgdGhlIDJEIFVNQVAgc3BhY2UuCgpgYGB7cn0KcGRhYyA8LSBSdW5VTUFQKHBkYWMsIAogICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gInBjYSIsIAogICAgICAgICAgICAgICAgZGltcyA9IDE6MjAsIAogICAgICAgICAgICAgICAgdW1hcC5tZXRob2QgPSAidXdvdCIsIAogICAgICAgICAgICAgICAgbi5jb21wb25lbnRzID0gMiwgCiAgICAgICAgICAgICAgICBuLmVwb2NocyA9IDc1MCwgCiAgICAgICAgICAgICAgICBuLm5laWdoYm9ycyA9IDUwLCAKICAgICAgICAgICAgICAgIG1ldHJpYyA9ICJjb3NpbmUiLCAKICAgICAgICAgICAgICAgIHNlZWQudXNlID0gNjI5LCAKICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKcDEgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidW1hcCIpICsgCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB1bm5hbWUodGFibGVhdTIwKCkpKSArIAogICAgICBsYWJzKHggPSAiVU1BUCAxIiwgeSA9ICJVTUFQIDIiKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDIsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkKcDEKYGBgCgojIyMgRml0LVNORQoKRm9yIGluZm9ybWF0aW9uIG9uIGhvdyB0byBpbnN0YWxsIHRoZSBgb3BlblRTTkVgIGltcGxlbWVudGF0aW9uIG9mIEZpdC1TTkUgYW5kIGhvdyB0byBydW4gdGhlIGFsZ29yaXRobSwgcGxlYXNlIHZpc2l0IFt0aGUgZXhjZWxsZW50IEdpdEh1YiByZXBvc2l0b3J5IG9mIFBhdmxpbiBQb2xpY2FyXShodHRwczovL2dpdGh1Yi5jb20vcGF2bGluLXBvbGljYXIvb3BlblRTTkUpLgoKRmlyc3Qgd2UnbGwgcnVuIGEgc2ltcGxlLCBzdGFuZGFyZCBGaXQtU05FIGVtYmVkZGluZy4gSXQncyBuZWNlc3NhcnkgdG8gbWFrZSB0aGUgUENBIGVtYmVkZGluZ3MgYWNjZXNzaWJsZSBieSBQeXRob24uCgpgYGB7cn0KcGNfZGYgPC0gRW1iZWRkaW5ncyhwZGFjLCByZWR1Y3Rpb24gPSAicGNhIikKYGBgCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCnBjX2RmID0gbnAuYXJyYXkoci5wY19kZikKIyBydW4gRml0LVNORQphZmZpbiA9IFBlcnBsZXhpdHlCYXNlZE5OKHBjX2RmLCBwZXJwbGV4aXR5PTUwLCBtZXRyaWM9J2Nvc2luZScsIHJhbmRvbV9zdGF0ZT02MjkpCmluaXQgPSBpbml0aWFsaXphdGlvbi5wY2EocGNfZGYsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmUxID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbiwgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZDEgPSB0c25lMS5vcHRpbWl6ZShuX2l0ZXI9MzUwLCBleGFnZ2VyYXRpb249MTIsIG1vbWVudHVtPTAuNikgCmVtYmVkMiA9IGVtYmVkMS5vcHRpbWl6ZShuX2l0ZXI9MTAwMCwgbW9tZW50dW09MC44KQpgYGAKClRoZSBlbWJlZGRpbmcgbG9va3MgZ29vZCwgYnV0IHRoZSBzdWJjbHVzdGVycyB3aXRoaW4gY2x1c3RlcnMgNSBhbmQgMTEgYXJlIHN0aWxsIGNsZWFybHkgc2VwYXJhdGVkLCBhbmQgYSBzbWFsbCBwYXJ0IG9mIGNsdXN0ZXIgMTIgaXMgZmFyIGZyb20gdGhlIHJlc3Qgb2YgdGhlIGNlbGxzIGluIHRoZSBjbHVzdGVyLgoKYGBge3J9CmVtYmVkIDwtIGFzLm1hdHJpeChweSRlbWJlZDIpCnJvd25hbWVzKGVtYmVkKSA8LSBjb2xuYW1lcyhwZGFjKQpwZGFjQHJlZHVjdGlvbnMkZml0c25lIDwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwMiA8LSBEaW1QbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJmaXRzbmUiKSArIAogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdW5uYW1lKHRhYmxlYXUyMCgpKSkgKyAKICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnAyCmBgYAoKV2UgdXNlIHRoZSBhYmlsaXR5IG9mIEZpdC1TTkUgdG8gY29uc2lkZXIgbXVsdGlwbGUgcGVycGxleGl0aWVzIGluIGFuIGF0dGVtcHQgdG8gcHJvdmlkZSBhIG1vcmUgYWNjdXJhdGUgcmVwcmVzZW50YXRpb24gb2YgYm90aCBsb2NhbCBhbmQgZ2xvYmFsIHN0cnVjdHVyZSBpbiBvdXIgZGF0YS4KCmBgYHtweXRob259CmFmZmluX2FubmVhbCA9IFBlcnBsZXhpdHlCYXNlZE5OKHBjX2RmLCBwZXJwbGV4aXR5PTE1MCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQp0c25lMiA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fYW5uZWFsLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkMyA9IHRzbmUyLm9wdGltaXplKG5faXRlcj0zNTAsIGV4YWdnZXJhdGlvbj0xMiwgbW9tZW50dW09MC41KQplbWJlZDQgPSBlbWJlZDEub3B0aW1pemUobl9pdGVyPTEwMDAsIGV4YWdnZXJhdGlvbj0xLCBtb21lbnR1bT0wLjgpCmFmZmluX2FubmVhbC5zZXRfcGVycGxleGl0eSgzMCkKZW1iZWQ1ID0gZW1iZWQ0Lm9wdGltaXplKG5faXRlcj01MDAsIG1vbWVudHVtPTAuOCkKYGBgCgpUaGUgcGVycGxleGl0eSBhbm5lYWxpbmcgaGFzbid0IHJlYWxseSBpbXByb3ZlZCBvciBldmVuIGNoYW5nZWQgdGhlIGVtYmVkZGluZyBtdWNoIGF0IGFsbC4KCmBgYHtyfQplbWJlZF9tdWx0aSA8LSBhcy5tYXRyaXgocHkkZW1iZWQ1KQpyb3duYW1lcyhlbWJlZF9tdWx0aSkgPC0gY29sbmFtZXMocGRhYykKcGRhY0ByZWR1Y3Rpb25zJGZpdHNuZV9tdWx0aSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfbXVsdGksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDMgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAiZml0c25lX211bHRpIikgKyAKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHVubmFtZSh0YWJsZWF1MjAoKSkpICsgCiAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwMwpgYGAKCkZpbmFsbHksIHdlJ2xsIHVzZSBhIG11bHRpc2NhbGUga2VybmVsIHRvIHJlcHJlc2VudCB0aGUgZGF0YSBpbiB0aGUgaGlnaC1kaW1lbnNpb25hbCBzcGFjZSBpbnN0ZWFkIG9mIHRoZSBkZWZhdWx0IEdhdXNzaWFuLiBUaGlzIGluIHRhbmRlbSB3aXRoIHRoZSBtdWx0aXBsZSBwZXJwbGV4aXR5IHZhbHVlcyB3aWxsIHByZXNlcnZlIGFzIG11Y2ggYXMgcG9zc2libGUgb2YgYm90aCBsb2NhbCBhbmQgZ2xvYmFsIHN0cnVjdHVyZS4KCmBgYHtweXRob259CmFmZmluX211bHRpID0gTXVsdGlzY2FsZShwY19kZiwgcGVycGxleGl0aWVzPVszMCwgMjAwXSwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQp0c25lMyA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fbXVsdGksIG5lZ2F0aXZlX2dyYWRpZW50X21ldGhvZD0nZmZ0JykKZW1iZWQ2ID0gdHNuZTMub3B0aW1pemUobl9pdGVyPTQ1MCwgZXhhZ2dlcmF0aW9uPTEyLCBtb21lbnR1bT0wLjYpCmVtYmVkNyA9IGVtYmVkNi5vcHRpbWl6ZShuX2l0ZXI9MTIwMCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYGBgCgpUaGUgbXVsdGlzY2FsZSB0cmljayBkb2Vzbid0IGNvbXBsZXRlbHkgZml4IHRoZSBlbWJlZGRpbmcgaXNzdWVzIGVpdGhlciwgYnV0IGl0IGRvZXMgY2xlYW4gdXAgYSBiaXQgb2YgdGhlIG5vaXNlIGluIHRoZSBwbG90LCBhbmQgaXQgZG9lcyBwbGFjZSB0aGUgc3ViY2x1c3RlcnMgaW4gY2x1c3RlcnMgMTEgYW5kIDUgY2xvc2VyIHRvZ2V0aGVyLiBXZSdsbCB1c2UgdGhpcyBlbWJlZGRpbmcgZ29pbmcgZm9yd2FyZCBhbmQgbWFrZSBzdXJlIHRvIGV4YW1pbmUgdGhvc2UgY2x1c3RlcnMgZm9yIHN1Ymdyb3VwcyB1c2luZyBgU0NJU1NPUlNgLgoKYGBge3J9CmVtYmVkX2tlcm4gPC0gYXMubWF0cml4KHB5JGVtYmVkNykKcm93bmFtZXMoZW1iZWRfa2VybikgPC0gY29sbmFtZXMocGRhYykKcGRhY0ByZWR1Y3Rpb25zJGZpdHNuZV9rZXJuPC0gQ3JlYXRlRGltUmVkdWNPYmplY3QoZW1iZWRkaW5ncyA9IGVtYmVkX2tlcm4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPSAiRml0U05FXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKCnA0IDwtIERpbVBsb3QocGRhYywgcmVkdWN0aW9uID0gImZpdHNuZV9rZXJuIikgKwogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdW5uYW1lKHRhYmxlYXUyMCgpKSkgKyAKICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnA0CmBgYAoKTG9va2luZyBhdCB0aGUgZW1iZWRkaW5nLCB3ZSBjYW4gc2VlIHRoYXQgY2x1c3RlcnMgMywgNCwgNSwgMTAsIGFuZCAxMSBjb250YWluIGNsZWFyIHNtYWxsIHN1YmNsdXN0ZXJzLiBJJ20gYWxzbyBpbnRyaWd1ZWQgYnkgdGhlIHNoYXBlIG9mIGNsdXN0ZXIgOC4gIFdlJ2xsIGJlIHN1cmUgdG8gaW52ZXN0aWdhdGUgZWFjaCBvZiB0aGVzZSBpbiB0dXJuLCBhbmQgYW5ub3RhdGUgdGhlIGdyb3VwcyB1c2luZyBtYXJrZXIgZ2VuZXMuCgpEdWUgdG8gdGhlIHdheSBgU2V1cmF0YCBhY2Nlc3NlcyBjZWxsIGVtYmVkZGluZ3MsIHdlJ2xsIG5lZWQgdG8gcmVwbGFjZSBvdXIgb3JpZ2luYWwgdC1TTkUgZGltZW5zaW9uIHJlZHVjdGlvbiBpbiBvdXIgYFNldXJhdGAgb2JqZWN0IHdpdGggdGhlIG5ldyBGaXQtU05FIHZlcnNpb24uIFdlJ2xsIGtlZXAgdGhlIG9yaWdpbmFsIEJhcm5lcy1IdXQgdC1TTkUgZW1iZWRkaW5nIHVuZGVyIGEgc2VwYXJhdGUgbmFtZS4KCmBgYHtyfQpwZGFjQHJlZHVjdGlvbnMkYmhfdHNuZSA8LSBwZGFjQHJlZHVjdGlvbnMkdHNuZQpwZGFjQHJlZHVjdGlvbnMkdHNuZSA8LSBwZGFjQHJlZHVjdGlvbnMkZml0c25lX2tlcm4KYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0Kcm0oZW1iZWQsIGVtYmVkX2tlcm4sIGVtYmVkX211bHRpLCBwY19kZikKYGBgCgojIFNpbmdsZVIgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uCgojIyBTaW5nbGUgQ2VsbCBSTkEtc2VxIFJlZmVyZW5jZSBEYXRhCgpIZXJlIHdlIHVzZSB0aGUgYFNpbmdsZVJgIHBhY2thZ2UgdG8gaWRlbnRpZnkgYnJvYWQgY2VsbCB0eXBlcy4gVGhlIHJlZmVyZW5jZSBkYXRhc2V0IHdlIGxvYWQgaXMgYW4gYHNjdHJhbnNmb3JtYC1ub3JtYWxpemVkIHZlcnNpb24gb2YgdGhlIHJhdyBjb3VudHMgYXZhaWxhYmxlIGluIGBzY1JOQXNlcTo6QmFyb25QYW5jcmVhc0RhdGEoKWAsIHdoaWNoIGNvbnNpc3RzIG9mIG5vcm1hbCBwYW5jcmVhcyBjZWxscyB0aGF0IHdlcmUgc2VxdWVuY2VkIGFuZCBhbm5vdGF0ZWQgYnkgdGhlIHJlc2VhcmNoZXJzLgoKYGBge3J9CnNjX3JlZiA8LSByZWFkUkRTKCIvVm9sdW1lcy9sYWJzL0hvbWUvSmVuIEplbiBZZWggTGFiL0phY2svc2NSTkFzZXEvU2V1cmF0L3NpbmdsZV9jZWxsX3JlZl9ub3JtYWxpemVkLlJkcyIpCnNjX3ByZWRzIDwtIFNpbmdsZVIodGVzdCA9IGRhdGEuZnJhbWUocGRhY0Bhc3NheXMkU0NUQGRhdGEpLCAKICAgICAgICAgICAgICAgICAgICByZWYgPSBzY19yZWYsIAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjX3JlZiRsYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImNsdXN0ZXIiLCAKICAgICAgICAgICAgICAgICAgICBjbHVzdGVycyA9IHBkYWMkc2V1cmF0X2NsdXN0ZXJzLCAKICAgICAgICAgICAgICAgICAgICBkZS5tZXRob2QgPSAid2lsY294IikKcGRhY1tbIlNpbmdsZVIubGFiZWxzLnNjIl1dIDwtIHNjX3ByZWRzJGxhYmVsc1ttYXRjaChwZGFjW1tdXVtbInNldXJhdF9jbHVzdGVycyJdXSwgcm93bmFtZXMoc2NfcHJlZHMpKV0KcGRhYyRTaW5nbGVSLmxhYmVscy5zYyA8LSBjYXNlX3doZW4ocGRhYyRTaW5nbGVSLmxhYmVscy5zYyA9PSAiYWNpbmFyIiB+ICJBY2luYXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5zYyA9PSAiYWN0aXZhdGVkX3N0ZWxsYXRlIiB+ICJBY3RpdmF0ZWQgU3RlbGxhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZGFjJFNpbmdsZVIubGFiZWxzLnNjID09ICJkdWN0YWwiIH4gIkR1Y3RhbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZGFjJFNpbmdsZVIubGFiZWxzLnNjID09ICJtYWNyb3BoYWdlIiB+ICJNYWNyb3BoYWdlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5zYyA9PSAidF9jZWxsIiB+ICJUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPT0gInF1aWVzY2VudF9zdGVsbGF0ZSIgfiAiUXVpZXNjZW50IFN0ZWxsYXRlIikKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlcmUncyBhIGxhcmdlIGltbXVuZSBwb3B1bGF0aW9uLCBhcyB3ZWxsIGFzIHNtYWxsZXIgZHVjdGFsLCBmaWJyb2JsYXN0IChkZW5vdGVkIGFjdGl2YXRlZCBhbmQgcXVpZXNjZW50IHN0ZWxsYXRlIGluIHRoZSByZWZlcmVuY2UgZGF0YXNldCksIGFuZCBhY2luYXIgZ3JvdXBzLiBUaGVzZSBicm9hZCBjZWxsIHR5cGVzIGxpbmUgdXAgd2l0aCB3aGF0IHdlIGV4cGVjdGVkIHRvIHNlZSBnaXZlbiB0aGUgYXV0aG9ycycgb3JpZ2luYWwgY2VsbCBjbHVzdGVyIGFubm90YXRpb25zLiAKCmBgYHtyfQpwNSA8LSBEaW1QbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAiU2luZ2xlUi5sYWJlbHMuc2MiKSArIAogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwNQpgYGAKCiMjIEJ1bGsgVGlzc3VlIFJOQS1zZXEgUmVmZXJlbmNlIERhdGEKClRoaXMgZGF0YXNldCBpcyBjb21wb3NlZCBvZiBsYWJlbGVkICYgbG9nLW5vcm1hbGl6ZWQgYnVsayBSTkEtc2VxIHNhbXBsZXMgZnJvbSB0aGUgSHVtYW4gUHJpbWFyeSBDZWxsIEF0bGFzLgoKYGBge3J9CmJ1bGtfcmVmIDwtIEh1bWFuUHJpbWFyeUNlbGxBdGxhc0RhdGEoKQpidWxrX3ByZWRzIDwtIFNpbmdsZVIodGVzdCA9IGRhdGEuZnJhbWUocGRhY0Bhc3NheXMkU0NUQGRhdGEpLCAKICAgICAgICAgICAgICAgICAgICAgIHJlZiA9IGJ1bGtfcmVmLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGJ1bGtfcmVmJGxhYmVsLm1haW4sIAogICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImNsdXN0ZXIiLCAKICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJzID0gcGRhYyRzZXVyYXRfY2x1c3RlcnMsIAogICAgICAgICAgICAgICAgICAgICAgZGUubWV0aG9kID0gIndpbGNveCIpCnBkYWNbWyJTaW5nbGVSLmxhYmVscy5idWxrIl1dIDwtIGJ1bGtfcHJlZHMkbGFiZWxzW21hdGNoKHBkYWNbW11dW1sic2V1cmF0X2NsdXN0ZXJzIl1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoYnVsa19wcmVkcykpXQpwZGFjJFNpbmdsZVIubGFiZWxzLmJ1bGsgPC0gY2FzZV93aGVuKHBkYWMkU2luZ2xlUi5sYWJlbHMuYnVsayA9PSAiQl9jZWxsIiB+ICJCIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrID09ICJFcGl0aGVsaWFsX2NlbGxzIiB+ICJFcGl0aGVsaWFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrID09ICJCX2NlbGwtIiB+ICJCIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrID09ICJUX2NlbGxzIiB+ICJUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrID09ICJFbmRvdGhlbGlhbF9jZWxscyIgfiAiRW5kb3RoZWxpYWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrKQpgYGAKClRoZSBidWxrIHJlZmVyZW5jZSBnaXZlcyB1cyBzb21ld2hhdCBtb3JlIGdyYW51bGFyIGxhYmVscyBmb3IgdGhlIGltbXVuZSBjZWxscywgYW5kIGNvbmZpcm1zIHRoZSBpZGVudGl0aWVzIG9mIHRoZSBkdWN0YWwgLyBlcGl0aGVsaWFsIGFuZCBzdHJvbWEgY2x1c3RlcnMuIFdlIHNlZSB0aGF0IHRoZSBjbHVzdGVycyBkZW5vdGVkIHF1aWVzY2VudCBzdGVsbGF0ZSBieSB0aGUgc2luZ2xlIGNlbGwgcmVmZXJlbmNlIGFyZSBoZXJlIGxhYmVsZWQgYXMgZW5kb3RoZWxpYWwgY2VsbHMsIGFuZCB0aGUgYWN0aXZhdGVkIHN0ZWxsYXRlIGNlbGxzIGFyZSBjb25maXJtZWQgdG8gYmUgZmlicm9ibGFzdHMuICAKCmBgYHtyfQpwNiA8LSBEaW1QbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAiU2luZ2xlUi5sYWJlbHMuYnVsayIpICsgCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnA2CmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CnJtKHNjX3ByZWRzLCBidWxrX3ByZWRzLCBidWxrX3JlZiwgc2NfcmVmKQpgYGAKCk9uZSBzaG91bGRuJ3QgdXNlIGBTaW5nbGVSYCBhcyB0aGUgZmluYWwgYXV0aG9yaXR5IGZvciBjZWxsIHR5cGVzLCBidXQgd2Ugd2VyZSBhYmxlIHRvIGNvbmZpcm0gdGhlIGlkZW50aXRpZXMgb2YgdGhlIGR1Y3RhbCBhbmQgZmlicm9ibGFzdCBjbHVzdGVycywgd2hpY2ggaXMgaW1wb3J0YW50IGZvciB0aGlzIGRhdGFzZXQgYXMgdGhlIGNlbGxzIHdlIGFyZSBtb3N0IGludGVyZXN0ZWQgaW4gYXJlIHRoZSBjYW5jZXItYXNzb2NpYXRlZCBmaWJyb2JsYXN0cyAoQ0FGcykuIAoKIyBDT05JQ1NtYXQgQ05WIEVzdGltYXRpb24KCk5leHQgd2UnbGwgYXR0ZW1wdCB0byBpZGVudGlmeSBtYWxpZ25hbnQgY2VsbHMgdXNpbmcgc2luZ2xlLWNlbGwgY29weSBudW1iZXIgdmFyaWF0aW9uIGVzdGltYXRpb24gYXMgaW1wbGVtZW50ZWQgaW4gdGhlIGBDT05DSVNtYXRgIHBhY2thZ2UuIERldGFpbHMgb2YgdGhlIEdNTSBtZXRob2RvbG9neSB1c2VkIGNhbiBiZSBmb3VuZCBbYXQgdGhlIERpYXogTGFiJ3MgR2l0SHViIHJlcG9zaXRvcnldKGh0dHBzOi8vZ2l0aHViLmNvbS9kaWF6bGFiL0NPTklDUykuIE5vdGU6IHRoaXMgc3RlcCBpcyBtZW1vcnktaW50ZW5zaXZlIGJlY2F1c2UgMSkgaXQgcmVxdWlyZXMgdGhlIHNwYXJzZSBjb3VudHMgbWF0cml4IHRvIGJlIGNhc3QgdG8gYSBkZW5zZSBtYXRyaXggYW5kIDIpIGEgbG90IG9mIEdhdXNzaWFuIG1peHR1cmUgbW9kZWxzIGdldCBlc3RpbWF0ZWQuIElmIHlvdXIgbWFjaGluZSBkb2Vzbid0IGhhdmUgYSBsb3Qgb2YgUkFNIGl0IG1pZ2h0IGJlIGJlc3QgdG8gc2tpcCB0aGlzIGFuZCBtYW51YWxseSBhbm5vdGF0ZSB0aGUgbWFsaWduYW50IGNlbGxzIGluc3RlYWQgdGhyb3VnaCB0aGUgdXNhZ2Ugb2Yga25vd24gY2Fub25pY2FsIG1hcmtlcnMgb3IgdGhlIGBWQU1gIHNpbmdsZS1jZWxsIEdTRUEgbWV0aG9kb2xvZ3kuIAoKYGBge3J9CmNocm9tX3JlZ2lvbnMgPC0gcmVhZC50YWJsZSgiL1ZvbHVtZXMvbGFicy9Ib21lL0plbiBKZW4gWWVoIExhYi9KYWNrL3NjUk5Bc2VxL2Nocm9tX2FybV9wb3NpdGlvbnMudHh0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSkKZ2VuZV9wb3MgPC0gZ2V0R2VuZVBvc2l0aW9ucyhyb3duYW1lcyhwZGFjKSkKY3BtIDwtIHQodChhcy5tYXRyaXgocGRhY0Bhc3NheXMkU0NUQGNvdW50cykpIC8gY29sU3Vtcyhhcy5tYXRyaXgocGRhY0Bhc3NheXMkU0NUQGNvdW50cykpKSAqIDEwXjUKY3BtIDwtIGxvZzIoY3BtICsgMSkKbm9ybV9mYWN0b3IgPC0gY2FsY05vcm1GYWN0b3JzKGNwbSkKY252X2VzdCA8LSBwbG90QWxsKG1hdCA9IGNwbSwgCiAgICAgICAgICAgICAgICAgICBub3JtRmFjdG9yID0gbm9ybV9mYWN0b3IsIAogICAgICAgICAgICAgICAgICAgcmVnaW9ucyA9IGNocm9tX3JlZ2lvbnMsIAogICAgICAgICAgICAgICAgICAgZ2VuZV9wb3MgPSBnZW5lX3BvcywgCiAgICAgICAgICAgICAgICAgICBmbmFtZSA9ICJFbHlhZGEiKQpgYGAKCiMjIFZpc3VhbGl6aW5nIENOVnMKCkFmdGVyIGVzdGltYXRpbmcgQ05Wcywgd2UgY2x1c3RlciB0aGUgY2VsbHMgaW50byAkayA9IDMkIGNsdXN0ZXJzLCB3aXRoIHRoZSBob3BlIG9mIGZpbmRpbmcgb25lIGxhcmdlIGNsdXN0ZXIgb2Ygbm9ybWFsIGNlbGxzIGFuZCB0d28gc21hbGxlciBjbHVzdGVycyBjb21wb3NlZCBvZiBDQUZzIGFuZCBQREFDIGNlbGxzLiAKCmBgYHtyfQpiaWNfdGFibGUgPC0gcmVhZC50YWJsZSgiLi9FbHlhZGFfQklDX0xSLnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEZBTFNFKQpjYW5kX3JlZ2lvbnMgPC0gcm93bmFtZXMoYmljX3RhYmxlW2JpY190YWJsZSRgQklDIGRpZmZlcmVuY2VgID4gMTAwMCAmIGJpY190YWJsZSRgTFJUIGFkai4gcC12YWxgIDwgLjAxLCBdKQpoaXN0MSA8LSBwbG90SGlzdG9ncmFtKGNudl9lc3RbLCBjYW5kX3JlZ2lvbnNdLCAKICAgICAgICAgICAgICAgICAgICAgICBjcG0sIAogICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJzID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgenNjb3JlVGhyZXNob2xkID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgY2VsbHR5cGVzID0gcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrLCAKICAgICAgICAgICAgICAgICAgICAgICBwYXRpZW50cyA9IHBkYWMkc2FtcGxlKQpgYGAKCldlIGFkZCB0aGUgbm9ybWFsIHZzLiBtYWxpZ25hbnQgY2VsbCBsYWJlbHMgaW4gdG8gb3VyIGBTZXVyYXRgIG9iamVjdCdzIG1ldGFkYXRhLCB0aGVuIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cy4gQXMgZXhwZWN0ZWQsIHRoZSBtYWxpZ25hbnQgY2VsbHMgYXJlIGxvY2F0ZWQgaW4gdGhlIGNsdXN0ZXJzIGlkZW50aWZpZWQgYnkgYFNpbmdsZVJgIGFzIGR1Y3RhbCBjZWxscyBhbmQgZmlicm9ibGFzdHMuIFRoaXMgaW5kaWNhdGVzIHRoYXQgYENPTklDU21hdGAgZGlkIGEgc29saWQgam9iIG9mIGVzdGltYXRpbmcgdGhlIENOVnMgLSBubyBlYXN5IGZlYXQgd2l0aCBzcGFyc2UsIG5vaXN5IHNpbmdsZS1jZWxsIGRhdGEuIAoKYGBge3J9Cm5vcm1hbCA8LSB3aGljaChoaXN0MSA9PSAyKQptYWxpZ25hbnQgPC0gd2hpY2goaGlzdDEgIT0gMikKcGRhY0BtZXRhLmRhdGEkbWFsaWcgPC0gaWZlbHNlKHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSAlaW4lIG5hbWVzKG5vcm1hbCksICJOb3JtYWwiLCAiTWFsaWduYW50IikKcDcgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gIm1hbGlnIikgKyAKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJaaXNzb3UxIiwgbiA9IDUpW2MoNSwgMildKSArIAogICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkKcDcKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0Kcm0oY3BtLCBiaWNfdGFibGUsIGNocm9tX3JlZ2lvbnMsIGNudl9lc3QsIGdlbmVfcG9zLCBjYW5kX3JlZ2lvbnMsIGhpc3QxLCBub3JtYWwsIG5vcm1fZmFjdG9yLCBtYWxpZ25hbnQpCmdjKCkgICMgbm90IHJlY29tbWVuZGVkLCBidXQgaXQgY291bGQgaGVscCB0aGlzIGRvY3VtZW50IGNvbXBpbGUsIHNvIC4uLgpgYGAKCiMgREVDT0RFUgoKTmV4dCwgd2UgdXNlIFtEci4gWGlhbmx1IFBlbmcncyBERUNPREVSXShodHRwczovL2dpdGh1Yi5jb20vbGF1cmFwZW5nL2RlY29kZXJyKSBpbiBvcmRlciB0byBkZWNvbnZvbHZlIHRoZSBkYXRhc2V0IGFuZCBhc3NpZ24gd2VpZ2h0cyB0byBlYWNoIGNlbGwgdXNpbmcgbm9uLW5lZ2F0aXZlIG1hdHJpeCBmYWN0b3JpemF0aW9uLiBXZSBjYWxjdWxhdGUgYmFzYWwgJiBjbGFzc2ljYWwgUERBQywgbm9ybWFsICYgYWN0aXZhdGVkIHN0cm9tYSwgaW1tdW5lLCBhbmQgZW5kb2NyaW5lICYgZXhvY3JpbmUgcGFuY3JlYXMgY29tcGFydG1lbnQgd2VpZ2h0cy4KCmBgYHtyfQpzYW1wbGVfd3RzX3Vuc2NhbGVkIDwtIERlY29uX3NpbmdsZV9zYW1wbGUoIlRDR0FfUk5Bc2VxX1BBQUQiLCBwZGFjQGFzc2F5cyRTQ1RAZGF0YSwgImdlbmVTeW1ib2wiKQpzYW1wbGVfd3RzIDwtIE5vcm1fUERBQ193ZWlnaHRzKHNhbXBsZV93dHNfdW5zY2FsZWQpCnBkYWMgPC0gQWRkTWV0YURhdGEocGRhYywgc2FtcGxlX3d0cyRJbW11bmUsICJpbW11bmUiKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHMkYmNSYXRpbywgImJjX3JhdGlvIikKcGRhYyA8LSBBZGRNZXRhRGF0YShwZGFjLCBzYW1wbGVfd3RzJEV4b2NyaW5lLCAiZXhvY3JpbmUiKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHMkRW5kb2NyaW5lLCAiZW5kb2NyaW5lIikKcGRhYyA8LSBBZGRNZXRhRGF0YShwZGFjLCBzYW1wbGVfd3RzX3Vuc2NhbGVkWywgOV0sICJiYXNhbCIpCnBkYWMgPC0gQWRkTWV0YURhdGEocGRhYywgc2FtcGxlX3d0c191bnNjYWxlZFssIDVdLCAiY2xhc3NpY2FsIikKcGRhYyA8LSBBZGRNZXRhRGF0YShwZGFjLCBzYW1wbGVfd3RzJE5vcm1hbFN0cm9tYSwgIm5vcm1fc3Ryb21hIikKcGRhYyA8LSBBZGRNZXRhRGF0YShwZGFjLCBzYW1wbGVfd3RzJEFjdGl2YXRlZFN0cm9tYSwgImFjdF9zdHJvbWEiKQpgYGAKCiMjIFZpc3VhbGl6aW5nIERFQ09ERVIgV2VpZ2h0cwoKIyMjIEJhc2FsIFBEQUMKClRoZSBiYXNhbCB3ZWlnaHRzIGFyZSBoaWdoZXN0IGluIGEgc3ViY2x1c3RlciBvZiB0aGUgZHVjdGFsIGdyb3VwIGlkZW50aWZpZWQgdGhyb3VnaCBgU2luZ2xlUmAuIFRoaXMgaXMgaW50ZXJlc3RpbmcgYXMgdGhlIGF1dGhvcnMgZGlkIG5vdCBmaW5kIGV2aWRlbmNlIG9mIHRoZSBiYXNhbCBzdWJ0eXBlIGluIHRoZWlyIHBhcGVyLiAKCmBgYHtyfQpwOCA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImJhc2FsIikgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICBOb0xlZ2VuZCgpCnA4CmBgYAoKIyMjIENsYXNzaWNhbCBQREFDCgpUaGUgY2xhc3NpY2FsIHdlaWdodHMgYXJlIGhpZ2hlc3QgaW4gYW5vdGhlciBzdWJjbHVzdGVyIG9mIHRoZSBkdWN0YWwgY2x1c3RlciwgYW5kIGNlbGxzIHdpdGggaGlnaCBjbGFzc2ljYWwgd2VpZ2h0cyBkbyBub3QgY29sbG9jYXRlIHdpdGggdGhvc2UgdGhhdCBoYXZlIGhpZ2ggYmFzYWwgd2VpZ2h0cy4gVGhlIHB1dGF0aXZlIGNsYXNzaWNhbCBhbmQgYmFzYWwgUERBQyBjZWxscyBhbHNvIGFsaWduIGNsb3NlbHkgd2l0aCB0aGUgY2VsbHMgaWRlbnRpZmllZCB0aHJvdWdoIGBDT05DSVNtYXRgIGFzIG1hbGlnbmFudC4gCgpgYGB7cn0KcDkgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJjbGFzc2ljYWwiKSArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgIE5vTGVnZW5kKCkKcDkKYGBgCgojIyMgRXhvY3JpbmUgUGFuY3JlYXMKClRoZSBjbHVzdGVyIGlkZW50aWZpZWQgdGhyb3VnaCBgU2luZ2xlUmAgYXMgYWNpbmFyIGNlbGxzIGlzIHRoZSBvbmx5IGNsdXN0ZXIgd2l0aCBoaWdoIGV4b2NyaW5lIHBhbmNyZWFzIHdlaWdodHMuIAoKYGBge3J9CnAxMCA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImV4b2NyaW5lIikgKwogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKQpwMTAKYGBgCgojIyMgRW5kb2NyaW5lIFBhbmNyZWFzCgpObyBjZWxscyBoYXZlIGhpZ2ggZW5kb2NyaW5lIHBhbmNyZWFzIHdlaWdodHMuIAoKYGBge3J9CnAxMSA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImVuZG9jcmluZSIpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDExCmBgYAoKIyMjIEltbXVuZQoKT25jZSBhZ2Fpbiwgd2UgY29uZmlybSB0aGUgbGFyZ2VuZXNzIG9mIHRoZSBpbW11bmUgY2VsbCBwb3B1bGF0aW9uIGluIHRoaXMgZGF0YXNldC4gCgpgYGB7cn0KcDEyIDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiaW1tdW5lIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDEyCmBgYAoKIyMjIE5vcm1hbCBTdHJvbWEKCkNlbGxzIHdpdGggaGlnaCBub3JtYWwgc3Ryb21hIHN0cm9tYSB3ZWlnaHRzIGFyZSBsb2NhdGVkIGluIHRoZSBjbHVzdGVyIGlkZW50aWZpZWQgYnkgYFNpbmdsZVJgIGFzIGJlaW5nIGNvbXBvc2VkIG9mIGVuZG90aGVsaWFsIGNlbGxzLiAKCmBgYHtyfQpwMTMgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJub3JtX3N0cm9tYSIpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDEzCmBgYAoKIyMjIEFjdGl2YXRlZCBTdHJvbWEKCkNlbGxzIHdpdGggaGlnaCBhY3RpdmF0ZWQgc3Ryb21hIHdlaWdodHMgYXJlIGFsc28gbG9jYXRlZCBpbiB0aGUgZmlicm9ibGFzdCBjbHVzdGVyLCBhbmQgZG8gbm90IGludGVyc2VjdCB3aXRoIHRoZSBjZWxscyB0aGF0IGhhdmUgaGlnaCBub3JtYWwgc3Ryb21hIHNjb3Jlcy4gVGhpcyBpbmRpY2F0ZXMgdGhhdCBgU0NJU1NPUlNgIHdpbGwgbW9zdCBsaWtlbHkgcGVyZm9ybSB3ZWxsIG9uIHRoZSBmaWJyb2JsYXN0IGNsdXN0ZXIgYW5kIGJlIGFibGUgdG8gcXVpY2tseSB0ZWFzZSBvdXQgdGhlIGNlbGwgc3VidHlwZXMuCgpgYGB7cn0KcDE0IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiYWN0X3N0cm9tYSIpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDE0CmBgYAoKIyBTQ0lTU09SUwoKTm93IHRoYXQgd2UgaGF2ZSByb3VnaCBsYWJlbHMgZnJvbSBgU2luZ2xlUmAsIENOVnMgZnJvbSBgQ09OSUNTbWF0YCwgYW5kIGNvbXBhcnRtZW50IHdlaWdodHMgZnJvbSBgREVDT0RFUmAsIHdlIHNob3VsZCBoYXZlIG1vcmUgdGhhbiBlbm91Z2ggY2VsbC1sZXZlbCBtZXRhZGF0YSB0byBsb29rIGZvciBhbmQgYW5ub3RhdGUgY2VsbCBzdWJ0eXBlcyB1c2luZyBgU0NJU1NPUlNgLiAKCiMjIEZpYnJvYmxhc3RzCgpUaGUgZmlicm9ibGFzdCBtYXJrZXIgZ2VuZXMgcHJvdmlkZWQgYnkgRWx5YWRhICpldCBhbCogbWF0Y2ggdGhlIGBTaW5nbGVSYCByZXN1bHRzIGRlZmluaW5nIGNsdXN0ZXIgOCBhcyBjb250YWluaW5nIGZpYnJvYmxhc3RzLiAKCmBgYHtyfQpwMTUgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDT0wxQTEiKSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIkNPTDFBMSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDE2IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ09MM0ExIikgKwogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh0aXRsZSA9ICJDT0wzQTEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxNyA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkxVTSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIkxVTSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDE4IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiRENOIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAiRENOIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDE1IHwgcDE2KSAvIChwMTcgfCBwMTgpCmBgYAoKIyMjIFJlY2x1c3RlcmluZwoKSGVyZSB3ZSB1c2UgYFJlY2x1c3RlckNlbGxzKClgIHRvIGlkZW50aWZ5IHN1YmNsdXN0ZXJzIHdpdGhpbiBjbHVzdGVyIDcuIFdlIGZpbmQgZm91ciBkaXN0aW5jdCBzdWJjbHVzdGVycy4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpmaWJybyA8LSBSZWNsdXN0ZXJDZWxscyhwZGFjLAogICAgICAgICAgICAgICAgICAgICAgICB3aGljaC5jbHVzdCA9IDgsCiAgICAgICAgICAgICAgICAgICAgICAgIG4udmFyaWFibGUuZ2VuZXMgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDIwLCAKICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbi52YWxzID0gYyguMSwgLjIsIC4zLCAuNCksIAogICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDUsIDEwLCAyMCwgMzApLCAKICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guZGltLnJlZHVjID0gInRzbmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgZG8ucGxvdCA9IEZBTFNFKQpmaWJyb19wYyA8LSBFbWJlZGRpbmdzKGZpYnJvLCAicGNhIikKYGBgCgpXZSdsbCBhZ2FpbiBydW4gRml0LVNORSBvbiB0aGUgcmVjbHVzdGVyZWQgY2VsbHMsIGZvciBjb25zaXN0ZW5jaWVzIHNha2UuIAoKYGBge3B5dGhvbn0KIyBpbXBvcnQgZGF0YQpmaWJyb19wYyA9IHIuZmlicm9fcGMKIyBydW4gRml0LVNORQphZmZpbl9maWJybyA9IFBlcnBsZXhpdHlCYXNlZE5OKGZpYnJvX3BjLCBwZXJwbGV4aXR5PTQwLCBtZXRyaWM9J2Nvc2luZScsIHJhbmRvbV9zdGF0ZT02MjkpCmluaXQgPSBpbml0aWFsaXphdGlvbi5wY2EoZmlicm9fcGMsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmVfZiA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fZmlicm8sIG5lZ2F0aXZlX2dyYWRpZW50X21ldGhvZD0nZmZ0JykKZW1iZWRfZjEgPSB0c25lX2Yub3B0aW1pemUobl9pdGVyPTI1MCwgZXhhZ2dlcmF0aW9uPTUsIG1vbWVudHVtPTAuNCkgCmVtYmVkX2YyID0gZW1iZWRfZjEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYGBgCgpQdWxsaW5nIHRoZSByZXN1bHRzIGJhY2sgaW50byBSIGFuZCB2aXN1YWxpemluZyB0aGVtIHNob3dzIGNsZWFyIHNlcGFyYXRpb24gYmV0d2VlbiB0aGUgc3ViY2x1c3RlcnMuIFRoZXJlJ3Mgc29tZSBub2lzZSBpbiBzdWJjbHVzdGVyIDAsIGJ1dCBvdGhlciB0aGFuIHRoYXQgdGhlIHJlZW1iZWRkaW5nIGxvb2tzIHNvbGlkLiAKCmBgYHtyfQplbWJlZF9maWJybyA8LSBhcy5tYXRyaXgocHkkZW1iZWRfZjIpCnJvd25hbWVzKGVtYmVkX2ZpYnJvKSA8LSBjb2xuYW1lcyhmaWJybykKZmlicm9AcmVkdWN0aW9ucyRiaF90c25lIDwtIGZpYnJvQHJlZHVjdGlvbnMkdHNuZQpmaWJyb0ByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZmlicm8sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPSAiRml0U05FXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDE5IDwtIERpbVBsb3QoZmlicm8sIHJlZHVjdGlvbiA9ICJ0c25lIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnAxOQpgYGAKCiMjIyBDZWxsIFR5cGUgSWRlbnRpZmljYXRpb24KCk5leHQsIHdlIHVzZSB0aGUgYFZBTWAgbWV0aG9kIG9mIHNpbmdsZSBjZWxsIGdlbmUgc2V0IGVucmljaG1lbnQgYW5hbHlzaXMgdG8gZGV0ZXJtaW5lIHdoaWNoIGNsdXN0ZXJzIGFyZSBlbnJpY2hlZCBmb3IgdGhlIGlDQUYgYW5kIG15Q0FGIG1hcmtlciBnZW5lcywgYXMgd2VsbCBhcyB0aGUgZ2VuZXJhbCBwYW4tQ0FGIG1hcmtlciBzZXQuIFdlIHVzZSB0aGUgbWFya2VyIGdlbmVzIGlkZW50aWZpZWQgYnkgdGhlIGF1dGhvcnMuIAoKYGBge3J9CmljYWZfZ2VuZXMgPC0gYygiSUw2IiwgIlBER0ZSQSIsICJDWENMMTIiLCAiQ0ZEIiwgIkxNTkEiLCAKICAgICAgICAgICAgICAgICJBR1RSMSIsICJIQVMxIiwgIkNYQ0wxIiwgIkNYQ0wyIiwgIkNDTDIiLCAiSUw4IikKbXljYWZfZ2VuZXMgPC0gYygiQUNUQTIiLCAiVEFHTE4iLCAiTU1QMTEiLCAiTVlMOSIsIAogICAgICAgICAgICAgICAgICJIT1BYIiwgIlBPU1ROIiwgIlRQTTEiLCAiVFBNMiIpCnBhbl9jYWZfZ2VuZXMgPC0gYygiQ09MMUExIiwgIkZBUCIsICJQRFBOIiwgIkRDTiIsICJWSU0iKQpnZW5lX3NldHMgPC0gbGlzdChpY2FmX2dlbmVzLCBteWNhZl9nZW5lcywgcGFuX2NhZl9nZW5lcykKbmFtZXMoZ2VuZV9zZXRzKSA8LSBjKCJpQ0FGIiwgIm15Q0FGIiwgIlBhbi1DQUYiKQpmb3IgKGkgaW4gc2VxKGdlbmVfc2V0cykpIHsKICBnZW5lX3NldHNbW2ldXSA8LSBnZW5lX3NldHNbW2ldXVtnZW5lX3NldHNbW2ldXSAlaW4lIHJvd25hbWVzKGZpYnJvKV0KfQpmaWJybyA8LSB2YW1Gb3JTZXVyYXQoZmlicm8sIAogICAgICAgICAgICAgICAgICAgICAgZ2VuZS5zZXQuY29sbGVjdGlvbiA9IGdlbmVfc2V0cywgCiAgICAgICAgICAgICAgICAgICAgICBnYW1tYSA9IFRSVUUpCkRlZmF1bHRBc3NheShmaWJybykgPC0gIlZBTWNkZiIKYGBgCgojIyMjIGlDQUZzICYgbXlDQUZzCgpXZSBjYW4gZWFzaWx5IGRlZmluZSBjbHVzdGVyIDAgYXMgdGhlIG15Q0FGIHBvcHVsYXRpb24sIGFuZCBjbHVzdGVycyAxIGFuZCAyIGFzIHRoZSBzbGlnaHRseSBzbWFsbGVyIGlDQUYgcG9wdWxhdGlvbi4gSW50ZXJlc3RpbmdseSwgY2x1c3RlciAzIHNob3dzIG5vIGVucmljaG1lbnQgd2hhdHNvZXZlciBmb3IgZWl0aGVyIHRoZSBpQ0FGIG9yIG15Q0FGIGdlbmUgc2V0cy4gCgpgYGB7cn0KcDIwIDwtIEZlYXR1cmVQbG90KGZpYnJvLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImlDQUYiKSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gImlDQUYgRW5yaWNobWVudCIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDIxIDwtIEZlYXR1cmVQbG90KGZpYnJvLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIm15Q0FGIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAibXlDQUYgRW5yaWNobWVudCIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAyMCB8IHAyMSkgLyBwMTkKYGBgCgojIyMjIGFwQ0FGcwoKSW50ZXJlc3RpbmdseSwgd2UgaGF2ZSBhIHNtYWxsIGNsdXN0ZXIgb2YgMjIgY2VsbHMgdGhhdCBkb2VzIG5vdCBhcHBlYXIgdG8gZXhwcmVzcyBhbnkgb2YgdGhlIGZpYnJvYmxhc3QsIENBRiwgcGVyaXZhc2N1bGFyLCBvciBlbmRvdGhlbGlhbCBtYXJrZXJzLiBXZSdsbCB1c2UgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gdGVzdGluZyB0byBmaW5kIG91dCB3aGF0IG1ha2VzIGl0IHVuaXF1ZSwgYW5kIGhvcGVmdWxseSBhbm5vdGF0ZSBpdC4gQWZ0ZXIgcGVyZm9ybWluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcywgd2UgZm91bmQgdGhhdCB0aGUgdG9wIDMgbWFya2VycyBmb3IgY2x1c3RlciA0IGFyZSBDTFUsIENENzQsIGFuZCBDUllBQi4gSW50ZXJlc3RpbmdseSwgQ0xVIGFuZCBDRDc0IHdlcmUgZm91bmQgdG8gYmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGluIHRoZSBhcENBRiBwb3B1bGF0aW9uIGRpc2NvdmVyZWQgaW4gdGhlIEtQQyBtb3VzZSBtb2RlbHMgb2YgQ0FGcyBpbiBFbHlhZGEgKmV0IGFsKi4KCmBgYHtyfQpEZWZhdWx0QXNzYXkoZmlicm8pIDwtICJTQ1QiCmZpYnJvX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoZmlicm8sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDEuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKQpmaWJyb19tYXJrZXJzICU+JSAKICBmaWx0ZXIoY2x1c3RlciA9PSA0KSAlPiUgCiAgYXJyYW5nZShkZXNjKGF2Z19sb2dGQykpCmBgYAoKV2UgcmUtcnVuIEdTRUEsIGFnYWluIHVzaW5nIHRoZSBgVkFNYCBwYWNrYWdlIGFuZCB0aGUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGZvciB0aGUgYXBDQUYgcG9wdWxhdGlvbiBhcyBkZWZpbmVkIGluIEVseWFkYSAqZXQgYWwqICh3aXRoIHRoZSBtb3VzZSBnZW5lIG5hbWVzIGNvbnZlcnRlZCB0byBIR05DIHN5bWJvbHMpLiBXZSBjYW4gc2VlIHRoYXQgdGhlIGFwQ0FGIHBhdGh3YXkgaXMgc3Ryb25nbHkgZW5yaWNoZWQgaW4gY2x1c3RlciAzIGFzIGNvbXBhcmVkIHRvIHRoZSBvdGhlciBDQUYgY2x1c3RlcnMuCgpgYGB7cn0KYXBjYWZfZ2VuZXMgPC0gYygiSExBLURRQjEiLCAiQ0Q3NCIsICJTQUEzUCIsICJTTFBJIikKZ2VuZV9zZXRzIDwtIGxpc3QoaWNhZl9nZW5lcywgbXljYWZfZ2VuZXMsIGFwY2FmX2dlbmVzLCBwYW5fY2FmX2dlbmVzKQpuYW1lcyhnZW5lX3NldHMpIDwtIGMoImlDQUYiLCAibXlDQUYiLCAiYXBDQUYiLCAiUGFuLUNBRiIpCmZvciAoaSBpbiBzZXEoZ2VuZV9zZXRzKSkgewogIGdlbmVfc2V0c1tbaV1dIDwtIGdlbmVfc2V0c1tbaV1dW2dlbmVfc2V0c1tbaV1dICVpbiUgcm93bmFtZXMoZmlicm8pXQp9CmZpYnJvIDwtIHZhbUZvclNldXJhdChmaWJybywgCiAgICAgICAgICAgICAgICAgICAgICBnZW5lLnNldC5jb2xsZWN0aW9uID0gZ2VuZV9zZXRzLCAKICAgICAgICAgICAgICAgICAgICAgIGdhbW1hID0gVFJVRSkKRGVmYXVsdEFzc2F5KGZpYnJvKSA8LSAiVkFNY2RmIgpwMjIgPC0gRmVhdHVyZVBsb3QoZmlicm8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiYXBDQUYiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh0aXRsZSA9ICJhcENBRiBFbnJpY2htZW50IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMjIgLyBwMTkKYGBgCgojIyMgVmlzdWFsaXphdGlvbgoKRmluYWxseSwgd2UgYWRkIGNlbGwgbGFiZWxzIHRvIG91ciBpZGVudGlmaWVkIGNsdXN0ZXJzLgoKYGBge3J9CmZpYnJvJGxhYmVsIDwtIGNhc2Vfd2hlbihmaWJybyRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJteUNBRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlicm8kc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiaUNBRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlicm8kc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiaUNBRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlicm8kc2V1cmF0X2NsdXN0ZXJzID09IDMgfiAiYXBDQUYiKQpwMjMgPC0gRGltUGxvdChmaWJybywgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJsYWJlbCIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAyMwpgYGAKCiMjIE5vcm1hbCBTdHJvbWEgQ2VsbHMKCldlIGh5cG90aGVzaXplIHRoYXQgdGhlIGNsdXN0ZXIgaWRlbnRpZmllZCBhcyBlbmRvdGhlbGlhbCBjZWxscyBieSBgU2luZ2xlUmAgY29udGFpbnMgb3VyIG5vcm1hbCBzdHJvbWEgcG9wdWxhdGlvbiwgYW5kIHBvdGVudGlhbGx5IHNvbWUgb3RoZXIgY2VsbCB0eXBlcyBhcyBpdCBjb250YWlucyB2aXNpYmxlIHN1YmNsdXN0ZXJzLiAKCiMjIyBSZWNsdXN0ZXJpbmcKCmBgYHtyfQplbmRvIDwtIFJlY2x1c3RlckNlbGxzKHBkYWMsIAogICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gMTIsIAogICAgICAgICAgICAgICAgICAgICAgIG4udmFyaWFibGUuZ2VuZXMgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICBuLlBDID0gMjAsIAogICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmRpbS5yZWR1YyA9ICJ0c25lIiwgCiAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKZW5kb19wYyA8LSBFbWJlZGRpbmdzKGVuZG8sICJwY2EiKQpgYGAKCkZvciBjb25zaXN0ZW5jaWVzJyBzYWtlLCB3ZSdsbCBydW4gRml0LVNORSBvbiB0aGUgcmVjbHVzdGVyZWQgb2JqZWN0LiAKCmBgYHtweXRob259CiMgaW1wb3J0IGRhdGEKZW5kb19wYyA9IHIuZW5kb19wYwojIHJ1biBGaXQtU05FCmFmZmluX2VuZG8gPSBQZXJwbGV4aXR5QmFzZWROTihlbmRvX3BjLCBwZXJwbGV4aXR5PTYwLCBtZXRyaWM9J2Nvc2luZScsIHJhbmRvbV9zdGF0ZT02MjkpCmluaXQgPSBpbml0aWFsaXphdGlvbi5wY2EoZW5kb19wYywgcmFuZG9tX3N0YXRlPTYyOSkKdHNuZV9lID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9lbmRvLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkX2UxID0gdHNuZV9lLm9wdGltaXplKG5faXRlcj0yNTAsIGV4YWdnZXJhdGlvbj0xMCwgbW9tZW50dW09MC42KSAKZW1iZWRfZTIgPSBlbWJlZF9lMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQpgYGAKCmBgYHtyfQplbWJlZF9lbmRvIDwtIGFzLm1hdHJpeChweSRlbWJlZF9lMikKcm93bmFtZXMoZW1iZWRfZW5kbykgPC0gY29sbmFtZXMoZW5kbykKZW5kb0ByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gZW5kb0ByZWR1Y3Rpb25zJHRzbmUKZW5kb0ByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZW5kbywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwMjQgPC0gRGltUGxvdChlbmRvLCByZWR1Y3Rpb24gPSAidHNuZSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwMjQKYGBgCgojIyMgUGVyaXZhc2N1bGFyIENlbGxzCgpCeSBleGFtaW5pbmcgdGhlIG1hcmtlciBnZW5lcyBwcm92aWRlZCBpbiB0aGUgRWx5YWRhIHBhcGVyLCB3ZSBkZWZpbmUgY2x1c3RlciAwIGFzIGJlaW5nIGNvbXBvc2VkIG9mIHBlcml2YXNjdWxhciBjZWxscy4gCgpgYGB7cn0KcDI1IDwtIEZlYXR1cmVQbG90KGVuZG8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSUdGQlA3IikgKwogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh0aXRsZSA9ICJJR0ZCUDciKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKwogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDI2IDwtIEZlYXR1cmVQbG90KGVuZG8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQUNUQTIiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh0aXRsZSA9ICJBQ1RBMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDI3IDwtIEZlYXR1cmVQbG90KGVuZG8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUkdTNSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIlJHUzUiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKwogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAyNSB8IHAyNiB8IHAyNykgLyBwMjQKYGBgCgojIyMgRW5kb3RoZWxpYWwgQ2VsbHMKCk5leHQsIHdlIHVzZSB0aGUgZ2VuZSBtYXJrZXJzIFBMVkFQIGFuZCBWV0YgKGFnYWluIHByb3ZpZGVkIGluIEVseWFkYSAqZXQgYWwqKSB0byBpZGVudGlmeSBjbHVzdGVyIDEgYXMgdGhlIGVuZG90aGVsaWFsIGNlbGxzLgoKYGBge3J9CnAyOCA8LSBGZWF0dXJlUGxvdChlbmRvLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlBMVkFQIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAiUExWQVAiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAyOSA8LSBGZWF0dXJlUGxvdChlbmRvLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlZXRiIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIlZXRiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAyOCB8IHAyOSkgLyBwMjQKYGBgCgojIyMgVmlzdWFsaXphdGlvbgoKRmlyc3Qgd2UgYWRkIGxhYmVscyB0byBvdXIgdHdvIGNsdXN0ZXJzLCB0aGVuIHdlIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cy4gCgpgYGB7cn0KZW5kbyRsYWJlbCA8LSBjYXNlX3doZW4oZW5kbyRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJQZXJpdmFzY3VsYXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgZW5kbyRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJFbmRvdGhlbGlhbCIpCnAzMCA8LSBEaW1QbG90KGVuZG8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAibGFiZWwiKSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMzAKYGBgCgojIyBUIENlbGxzCgpHb2luZyBiYWNrIHRvIHRoZSBtYWluIGBTZXVyYXRgIG9iamVjdCwgd2Ugc2hvdWxkIGhhdmUgYSBsYXJnZSBwb3B1bGF0aW9uIG9mIFQgYW5kIE5LIGNlbGxzIHRoYXQgd2FycmFudHMgZnVydGhlciBpbnZlc3RpZ2F0aW9uLiBVc2luZyBDRDNEIGV4cHJlc3Npb24gd2UgY2FuIGVhc2lseSBpZGVudGlmeSBjbHVzdGVycyAwLCAzLCBhbmQgNyBhcyB0aGUgbWl4ZWQgVCAmIE5LIGNlbGxzLiBXZSBhbHJlYWR5IHNlZSBzb21lIGdvb2Qgc2VwYXJhdGlvbiwgc28gcmVjbHVzdGVyaW5nIHRoZSBjZWxscyBzaG91bGQgaGF2ZSBnb29kIHJlc3VsdHMuIAoKYGBge3J9CnAzMSA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEM0QiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAzMSAvIHA0CmBgYAoKIyMjIFR1bW9yCgpgYGB7cn0Kbmt0X3R1bW9yIDwtIHN1YnNldChwZGFjLCBzdWJzZXQgPSBzZXVyYXRfY2x1c3RlcnMgJWluJSBjKDAsIDMsIDcpICYgY29uZGl0aW9uID09ICJQREFDIikKYGBgCgojIyMjIFJlY2x1c3RlcmluZwoKSGVyZSB3ZSBydW4gYFJlY2x1c3RlckNlbGxzKClgLCB3aGlsZSB0cmVhdGluZyB0aGUgTksgJiBUIGNlbGwgY2x1c3RlcnMgYXMgb25lIGxhcmdlIGdyb3VwLiBUaGlzIHdpbGwgaG9wZWZ1bGx5IGFsbG93IHVzZSB0byBlbHVjaWRhdGUgVCBjZWxsIHN1YnR5cGVzLiBXZSB1c2UgZmV3ZXIgUENzIGZvciB0aGVzZSBjZWxscyBzaW5jZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBpbW11bmUgY2VsbHMgYXJlIHN1YnRsZSwgYW5kIGFkZGluZyBtb3JlIFBDcyB3aWxsIG1vc3QgbGlrZWx5IG9ubHkgY29udHJpYnV0ZSBub2lzZSB0byBvdXIgYW5hbHlzZXMuIAoKYGBge3J9Cm5rdF90dW1vciA8LSBSZWNsdXN0ZXJDZWxscyhua3RfdHVtb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guY2x1c3QgPSBsaXN0KDAsIDMsIDcpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlLmNsdXN0ZXJzID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnZhcmlhYmxlLmdlbmVzID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLlBDID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgay52YWxzID0gYygzMCwgNDAsIDUwLCA2MCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbi52YWxzID0gYyguMSwgLjIsIC4zKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaC5kaW0ucmVkdWMgPSAidHNuZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQpua3RfdHVtb3JfcGMgPC0gRW1iZWRkaW5ncyhua3RfdHVtb3IsICJwY2EiKQpgYGAKCk9uY2UgYWdhaW4gd2UnbGwgcnVuIEZpdC1TTkUgb24gdGhlIHJlY2x1c3RlcmVkIGNlbGxzLiAKCmBgYHtweXRob259CiMgaW1wb3J0IGRhdGEKbmt0X3R1bW9yX3BjID0gci5ua3RfdHVtb3JfcGMKIyBydW4gRml0LVNORQphZmZpbl9ua3RfdHVtb3IgPSBQZXJwbGV4aXR5QmFzZWROTihua3RfdHVtb3JfcGMsIHBlcnBsZXhpdHk9MTgwLCBtZXRyaWM9J2Nvc2luZScsIHJhbmRvbV9zdGF0ZT02MjkpCmluaXQgPSBpbml0aWFsaXphdGlvbi5wY2Eobmt0X3R1bW9yX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX25rdF90dW1vciA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fbmt0X3R1bW9yLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkX25rdF90dW1vcjEgPSB0c25lX25rdF90dW1vci5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249NCwgbW9tZW50dW09MC42KSAKZW1iZWRfbmt0X3R1bW9yMiA9IGVtYmVkX25rdF90dW1vcjEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYWZmaW5fbmt0X3R1bW9yLnNldF9wZXJwbGV4aXR5KDc1KQplbWJlZF9ua3RfdHVtb3IzID0gZW1iZWRfbmt0X3R1bW9yMi5vcHRpbWl6ZShuX2l0ZXI9MywgZXhhZ2dlcmF0aW9uPTIsIG1vbWVudHVtPTAuMSkKZW1iZWRfbmt0X3R1bW9yNCA9IGVtYmVkX25rdF90dW1vcjMub3B0aW1pemUobl9pdGVyPTUwMCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuNikKYGBgCgpUaGUgcmVlbWJlZGRpbmcgaXNuJ3QgcGVyZmVjdCwgd2hpY2ggd2Ugc29tZXdoYXQgZXhwZWN0ZWQgYXMgaW1tdW5lIGNlbGxzIGFyZSBkaWZmaWN1bHQgdG8gdGVsbCBhcGFydCBiYXNlZCBvbiB0aGUgdHJhbnNjcmlwdG9tZSBhbG9uZS4gCgpgYGB7cn0KZW1iZWRfbmt0X3R1bW9yIDwtIGFzLm1hdHJpeChweSRlbWJlZF9ua3RfdHVtb3I0KQpyb3duYW1lcyhlbWJlZF9ua3RfdHVtb3IpIDwtIGNvbG5hbWVzKG5rdF90dW1vcikKbmt0X3R1bW9yQHJlZHVjdGlvbnMkYmhfdHNuZSA8LSBua3RfdHVtb3JAcmVkdWN0aW9ucyR0c25lCm5rdF90dW1vckByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfbmt0X3R1bW9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbCA9IFRSVUUpCnAzMiA8LSBEaW1QbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiKSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkKcDMyCmBgYAoKIyMjIyBDZWxsIFR5cGUgSWRlbnRpZmljYXRpb24KCiMjIyMjIENENCsgVAoKQ0x1c3RlcnMgMCBhbmQgMSBjb250YWluIG91ciBDRDQrIFQgY2VsbHMsIHdoaWNoIHdlIGNoYXJhY3Rlcml6ZSB1c2luZyBJTDdSIGFzIHdlIGRpZCBpbiB0aGUgUEJNQzNrIHZpZ25ldHRlLiBJdCdzIHNvbWV3aGF0IG91dHNpZGUgb2Ygb3VyIHNjb3BlIGhlcmUgdG8gZGV0ZXJtaW5lIHdoaWNoIHN1YnR5cGUgZWFjaCBjbHVzdGVyIGJlbG9uZ3MgdG8sIHNvIHdlJ2xsIHNpbXBseSBhc3NpZ24gYm90aCBjbHVzdGVycyB0aGUgc2FtZSBsYWJlbCBhbmQgbW92ZSBvbi4gCgpgYGB7cn0KcDMzIDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJJTDdSIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDM0IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDY5IikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAzMyB8IHAzNCkgLyBwMzIKYGBgCgojIyMjIyBULXJlZ3MKCkNsdXN0ZXIgMyBjb250YWlucyB0aGUgcmVndWxhdG9yeSBUIGNlbGxzLiAKCmBgYHtyfQpwMzUgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIklMMlJBIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDM2IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJGT1hQMyIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMzUgfCBwMzYpIC8gcDMyCmBgYAoKIyMjIyMgUHJvbGlmZXJhdGluZyBULXJlZ3MKCldlIGNhbiBmaW5kIHRoZSBwcm9saWZlcmF0aW5nIFQtcmVncyBpbiBjbHVzdGVyIDcuIAoKYGBge3J9CnAzNyA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiVE9QMkEiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMzcgLyBwMzIKYGBgCgojIyMjIyBNYXN0CgpNYXN0IGNlbGxzIGNhbiBiZSBpZGVudGlmaWVkIHVzaW5nIFRQU0FCMSBleHByZXNzaW9uIGluIGNsdXN0ZXIgNi4gCgpgYGB7cn0KcDM4IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJUUFNBQjEiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMzggLyBwMzIKYGBgCgojIyMjIyBOSwoKTktHNyBhbmQgUFJGMSBzaG93IHVzIHRoZSBOSyBjZWxscyBpbiBjbHVzdGVyIDUuIAoKYGBge3J9CnAzOSA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTktHNyIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA0MCA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUFJGMSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMzkgfCBwNDApIC8gcDMyCmBgYAoKIyMjIyMgQ0Q4KyBUCgpXZSB1c2UgQ0Q4QSBhbmQgQ0QyIHRvIHJldmVhbCB0aGUgQ0Q4KyBUIGNlbGxzIHdpdGhpbiBjbHVzdGVycyAyIGFuZCA0LiAKCmBgYHtyfQpwNDEgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEOEEiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNDIgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEMiIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNDEgfCBwNDIpIC8gcDMyCmBgYAoKIyMjIyBJbnRlcm1lZGlhdGUgTW9ub2N5dGUKCkxhc3RseSwgd2UgaGF2ZSBjbHVzdGVyIDgsIHdoaWNoIGRvZXNuJ3QgaGlnaGx5IGV4cHJlc3Mgb3VyIHBhbi1UL05LIGNlbGwgbWFya2VycyBDRDNEIGFuZCBDRDIuIEl0IGNvdWxkIGJlIGEgbXllbG9pZCBjZWxsIGNsdXN0ZXIgdGhhdCB3YXMgbWlzdGFrZW5seSBncm91cGVkIHdpdGggdGhlIFQvTksgY2VsbHMuIFdlJ2xsIHN0YXJ0IHdpdGggYSBXaWxjb3hvbiB0ZXN0IHRvIGRldGVybWluZSBpdHMgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzLiAKCmBgYHtyfQpjbHVzdDhfbWFya2VycyA8LSBGaW5kQWxsTWFya2Vycyhua3RfdHVtb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnVzZSA9ICJ3aWxjb3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZGlmZi5wY3QgPSAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkgJT4lIAogICAgICAgICAgICAgICAgICBmaWx0ZXIoY2x1c3RlciA9PSA4LCBwX3ZhbF9hZGogPCAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKDEgLSBwX3ZhbF9hZGopKSAlPiUgCiAgICAgICAgICAgICAgICAgIHByaW50KCkKYGBgCgpJbnRlcmVzdGluZ2x5LCBzZXZlcmFsIFtpbnRlcm1lZGlhdGUgbW9ub2N5dGUgbWFya2Vyc10oaHR0cHM6Ly93d3cuZnJvbnRpZXJzaW4ub3JnL2FydGljbGVzLzEwLjMzODkvZmltbXUuMjAxOS4wMjAzNS9mdWxsI0IzKSAtIExZWiwgSExBLURSQSwgQ0Q3NCwgYW5kIEhMQS1EUEIxIC0gYXJlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBpbiBjbHVzdGVyIDguIAoKV2UnbGwgcGxvdCBzb21lIG9mIHRob3NlIG1hcmtlcnMgYmVsb3cuIAoKYGBge3J9CnA0MyA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTFlaIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDQ0IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJITEEtRFJBIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDQ1IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDc0IikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDQ2IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJITEEtRFBCMSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCigocDQzIHwgcDQ0KSAvIChwNDUgfCBwNDYpKSAvIHAzMgpgYGAKCgojIyMjIFZpc3VhbGl6YXRpb24KCldlIGFkZCBsYWJlbHMgdG8gb3VyIFQgY2VsbCBgU2V1cmF0YCBvYmplY3QgYW5kIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cy4gCgpgYGB7cn0Kbmt0X3R1bW9yJGxhYmVsIDwtIGNhc2Vfd2hlbihua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDAgfiAiQ0Q0KyBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSAxIH4gIkNENCsgVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF90dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gMiB+ICJDRDgrIFQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDMgfiAiVC1yZWciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDQgfiAiQ0Q4KyBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSA1IH4gIk5LIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSA2IH4gIk1hc3QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDcgfiAiUHJvbGlmZXJhdGluZyBULXJlZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF90dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gOCB+ICJJbnRlcm1lZGlhdGUgTW9ub2N5dGUiKQpwNDcgPC0gRGltUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAibGFiZWwiKSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnA0NwpgYGAKCiMjIyBBZGphY2VudCBOb3JtYWwKCmBgYHtyfQpua3Rfbm9ybSA8LSBzdWJzZXQocGRhYywgc3Vic2V0ID0gc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygwLCAzLCA3KSAmIGNvbmRpdGlvbiA9PSAiQWRqTm9ybSIpCmBgYAoKIyMjIyBSZWNsdXN0ZXJpbmcKCmBgYHtyfQpua3Rfbm9ybSA8LSBSZWNsdXN0ZXJDZWxscyhua3Rfbm9ybSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gbGlzdCgwLCAzLCA3KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlLmNsdXN0ZXJzID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udmFyaWFibGUuZ2VuZXMgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgay52YWxzID0gYyg1LCAxMCwgMTUsIDIwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjEsIC4yLCAuMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaC5kaW0ucmVkdWMgPSAidHNuZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKbmt0X25vcm1fcGMgPC0gRW1iZWRkaW5ncyhua3Rfbm9ybSwgInBjYSIpCmBgYAoKQXMgd2l0aCB0aGUgb3RoZXIgcmVjbHVzdGVyaW5ncywgd2UnbGwgcnVuIEZpdC1TTkUgaW4gb3JkZXIgdG8gKGhvcGVmdWxseSkgb2J0YWluIGEgYmV0dGVyIGxvdy1kaW1lbnNpb25hbCBlbWJlZGRpbmcgb2Ygb3VyIGNlbGxzLgoKYGBge3B5dGhvbn0KIyBpbXBvcnQgZGF0YQpua3Rfbm9ybV9wYyA9IHIubmt0X25vcm1fcGMKIyBydW4gRml0LVNORQphZmZpbl9ua3Rfbm9ybSA9IFBlcnBsZXhpdHlCYXNlZE5OKG5rdF9ub3JtX3BjLCBwZXJwbGV4aXR5PTEwMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKG5rdF9ub3JtX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX25rdF9ub3JtID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9ua3Rfbm9ybSwgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9ua3Rfbm9ybTEgPSB0c25lX25rdF9ub3JtLm9wdGltaXplKG5faXRlcj0yNTAsIGV4YWdnZXJhdGlvbj0xMiwgbW9tZW50dW09MC42KSAKZW1iZWRfbmt0X25vcm0yID0gZW1iZWRfbmt0X25vcm0xLm9wdGltaXplKG5faXRlcj03NTAsIGV4YWdnZXJhdGlvbj0xLCBtb21lbnR1bT0wLjgpCmFmZmluX25rdF9ub3JtLnNldF9wZXJwbGV4aXR5KDIwKQplbWJlZF9ua3Rfbm9ybTMgPSBlbWJlZF9ua3Rfbm9ybTIub3B0aW1pemUobl9pdGVyPTIwLCBleGFnZ2VyYXRpb249MiwgbW9tZW50dW09MC43KQplbWJlZF9ua3Rfbm9ybTQgPSBlbWJlZF9ua3Rfbm9ybTMub3B0aW1pemUobl9pdGVyPTUwMCkKYGBgCgpgYGB7cn0KZW1iZWRfbmt0X25vcm0gPC0gYXMubWF0cml4KHB5JGVtYmVkX25rdF9ub3JtNCkKcm93bmFtZXMoZW1iZWRfbmt0X25vcm0pIDwtIGNvbG5hbWVzKG5rdF9ub3JtKQpua3Rfbm9ybUByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gbmt0X25vcm1AcmVkdWN0aW9ucyR0c25lCm5rdF9ub3JtQHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9ua3Rfbm9ybSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwNDggPC0gRGltUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiKSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkKcDQ4CmBgYAoKIyMjIyBDZWxsIFR5cGUgSWRlbnRpZmljYXRpb24KCkZpcnN0IHdlJ2xsIHVzZSBhIFdpbGNveG9uIHRlc3QgdG8gZGV0ZXJtaW5lIHdoaWNoIGdlbmVzIGNoYXJhY3Rlcml6ZSBlYWNoIGNsdXN0ZXIuIAoKYGBge3J9Cm5rdF9ub3JtX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMobmt0X25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZGlmZi5wY3QgPSAuMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkKbmt0X25vcm1fbWFya2VycyAgJT4lIAogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICB0b3BfbihuID0gMiwgd3QgPSBhdmdfbG9nRkMpCmBgYAoKIyMjIyMgQ0Q0KyBUCgpXZSBjYW4gdXNlIElMN1IgYW5kIFMxMDBBNCBleHByZXNzaW9uIHRvIGlkZW50aWZ5IHRoZSBtZW1vcnkgQ0Q0KyBUIGNlbGxzIGluIGNsdXN0ZXIgMC4gSUw3UiBhbmQgQ0NSNyBpZGVudGlmeSB0aGUgbmFpdmUgQ0Q0KyBUIGNlbGxzIGluIHRoZSBhZGphY2VudCBjbHVzdGVyIDQuIAoKYGBge3J9CnA0OSA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJJTDdSIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDUwIDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBNCIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA1MSA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDQ1I3IikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA1MCB8IHA0OSB8IHA1MSkgLyBwNDgKYGBgCgojIyMjIyBDRDgrIFQKCk5leHQgd2UgcmV2ZWFsIHRoZSBDRDgrIFQgY2VsbHMgaW4gY2x1c3RlcnMgMSBhbmQgMiB3aXRoIENEOEEsIGFzIHBlciB1c3VhbC4gCgpgYGB7cn0KcDUyIDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEOEEiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNTIgLyBwNDgKYGBgCgojIyMjIyBULXJlZwoKVGhlIFQtcmVnIGNsdXN0ZXIsIGNsdXN0ZXIgNSwgaXMgaWRlbnRpZmllZCB1c2luZyBUSUdJVCBhbmQgRk9YUDMuIAoKYGBge3J9CnA1MyA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJUSUdJVCIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA1NCA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJGT1hQMyIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNTMgfCBwNTQpIC8gcDQ4CmBgYAoKIyMjIyMgTksKClRoZSBuYXR1cmFsIGtpbGxlcnMgY2FuIGJlIGZvdW5kIGluIGNsdXN0ZXIgNCB0aHJvdWdoIHRoZWlyIGV4cHJlc3Npb24gb2YgUFJGMSBhbmQgTktHNy4gVGhlIE5LRzcgZXhwcmVzc2lvbiBhbHNvIGNvbmZpcm1zIHRoZSBpZGVudGl0aWVzIG9mIHRoZSBDRDgrIFQgY2VsbHMgd2UganVzdCBhbm5vdGF0ZWQuIAoKYGBge3J9CnA1NSA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJQUkYxIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDU2IDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIk5LRzciKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDU1IHwgcDU2KSAvIHA0OApgYGAKCiMjIyMjIFByb2xpZmVyYXRpbmcgVC1yZWcKClRoZSB0aW55IHByb2xpZmVyYXRpbmcgVC1yZWcgcG9wdWxhdGlvbiBpbiBjbHVzdGVyIDcgaXMgY2hhcmFjdGVyaXplZCBieSBUT1AyQS4gCgpgYGB7cn0KcDU3IDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlRPUDJBIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDU3IC8gcDQ4CmBgYAoKIyMjIyBJbnRlcm1lZGlhdGUgTW9ub2N5dGUKCkFmdGVyIHJ1bm5pbmcgYW5vdGhlciBXaWxjb3hvbiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB0ZXN0IHNwZWNpZmljYWxseSBmb3IgdGhlIGxhc3QgY2x1c3RlciwgY2x1c3RlciA2LCB3ZSBjYW4gc2VlIHRoYXQgc2V2ZXJhbCBvZiB0aGUgbXllbG9pZCBtYXJrZXIgZ2VuZXMgZnJvbSBFbHlhZGEgKmV0IGFsKiBhcmUgdXByZWd1bGF0ZWQgLSBDRDY4LCBMWVosIENEMTQsIEhMQS1EUkEuIExTVDEgaXMgYWxzbyBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZDsgW0xTVDEgaXMgaW52b2x2ZWQgaW4gbW9ub2N5dGUgZGlmZmVyZW50aWF0aW9uXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM0MDE1OTE0LykuIExhc3RseSwgVFlST0JQLCBha2EgREFQMTIsIFtpcyBhc3NvY2lhdGVkIHdpdGggaW5mbGFtbWF0aW9uIGFuZCBpcyBoaWdobHkgZXhwcmVzc2VkIGluIGFjdGl2YXRlZCBtb25vY3l0ZXNdKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9hYnMvcGlpL1MwODg5MTU5MTExMDAwNzQyKS4gCgpgYGB7cn0KRmluZE1hcmtlcnMobmt0X25vcm0sIAogICAgICAgICAgICBpZGVudC4xID0gNiwgCiAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgIG1pbi5wY3QgPSAuMywgCiAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSwgCiAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KSAlPiUgCiAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkgCmBgYAoKV2UgcGxvdCBzb21lIG9mIHRoZSBpbnRlcm1lZGlhdGUgbW9ub2N5dGUgbWFya2VyIGdlbmVzLiBXZSBjYW4gc2F5IHdpdGggcmVhc29uYWJsZSBjb25maWRlbmNlIHRoYXQgY2x1c3RlciA2IGNvbnRhaW5zIGludGVybWVkaWF0ZSBtb25vY3l0ZXMuIAoKYGBge3J9CnA1OCA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJMWVoiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNTkgPC0gRmVhdHVyZVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSExBLURSQSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA2MCA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJMU1QxIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDYxIDwtIEZlYXR1cmVQbG90KG5rdF9ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlRZUk9CUCIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCigocDU4IHwgcDU5KSAvIChwNjAgfCBwNjEpKSAvIHA0OApgYGAKCiMjIyMgVmlzdWFsaXphdGlvbgoKV2UgYWRkIGZpbmFsIGNlbGwgbGFiZWxzIHRvIG91ciA4IGNlbGwgY2x1c3RlcnMuIAoKYGBge3J9Cm5rdF9ub3JtJGxhYmVsIDwtIGNhc2Vfd2hlbihua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJNZW1vcnkgQ0Q0KyBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJDRDgrIFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiQ0Q4KyBUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF9ub3JtJHNldXJhdF9jbHVzdGVycyA9PSAzIH4gIk5haXZlIENENCsgVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gNCB+ICJOSyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gNSB+ICJULXJlZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDYgfiAiSW50ZXJtZWRpYXRlIE1vbm9jeXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gNyB+ICJQcm9saWZlcmF0aW5nIFQtcmVnIikKcDYyIDwtIERpbVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAibGFiZWwiKSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnA2MgpgYGAKCiMjIER1Y3RhbCBDZWxscwoKIyMjIFJlY2x1c3RlcmluZwoKV2UgdXNlIEtSVDggZXhwcmVzc2lvbiB0byBzaG93IHRoZSBkdWN0YWwgY2VsbHMgcmVzaWRpbmcgaW4gY2x1c3RlcnMgNSBhbmQgMTAuIFdlIG5vdGUgdGhhdCBzb21lIHJlZ2lvbnMgb2YgY2x1c3RlcnMgNSBhbmQgMTAgaGF2ZSBubyBLUlQ4IGV4cHJlc3Npb24sIHdoaWNoIGxpa2VseSBtZWFucyB0aGF0IHRoZXkgYXJlIGNvbXBvc2VkIG9mIGRpZmZlcmVudCBjZWxsIHR5cGVzLiAKCmBgYHtyfQpwNjMgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJLUlQ4IikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDYzIC8gcDQKYGBgCgpXZSBydW4gYFNDSVNTT1JTYCwgdGhlbiB1c2UgYSBXaWxjb3hvbiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB0ZXN0IHRvIGRldGVybWluZSBwb3RlbnRpYWwgbWFya2VycyBmb3IgZWFjaCBjbHVzdGVyLiAKCmBgYHtyfQpkdWN0YWwgPC0gUmVjbHVzdGVyQ2VsbHMocGRhYywgCiAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaC5jbHVzdCA9IGxpc3QoNSwgMTApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlLmNsdXN0ZXJzID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBuLnZhcmlhYmxlLmdlbmVzID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBuLlBDID0gMjAsIAogICAgICAgICAgICAgICAgICAgICAgICAgay52YWxzID0gYygxMCwgMjAsIDMwLCA0MCksIAogICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbi52YWxzID0gYyguMSwgLjIsIC4zLCAuNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guZGltLnJlZHVjID0gInRzbmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlZG8uZW1iZWRkaW5nID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkby5wbG90ID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpCmR1Y3RhbF9tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKGR1Y3RhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLmRpZmYucGN0ID0gLjIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkgJT4lIAogICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KQpkdWN0YWxfbWFya2VycyAlPiUgCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogIHRvcF9uKG4gPSAzLCB3dCA9IGF2Z19sb2dGQykKYGBgCgpBZ2Fpbiwgd2UnbGwgcnVuIEZpdC1TTkUgb24gdGhlIHJlY2x1c3RlcmVkIGNlbGxzLiAKCmBgYHtyfQpkdWN0X3BjIDwtIEVtYmVkZGluZ3MoZHVjdGFsLCByZWR1Y3Rpb24gPSAicGNhIikKYGBgCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCmR1Y3RfcGMgPSByLmR1Y3RfcGMKIyBydW4gRml0LVNORQphZmZpbl9kdWN0ID0gUGVycGxleGl0eUJhc2VkTk4oZHVjdF9wYywgcGVycGxleGl0eT0yMDAsIG1ldHJpYz0nY29zaW5lJywgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShkdWN0X3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX2R1Y3QgPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluX2R1Y3QsIG5lZ2F0aXZlX2dyYWRpZW50X21ldGhvZD0nZmZ0JykKZW1iZWRfZDEgPSB0c25lX2R1Y3Qub3B0aW1pemUobl9pdGVyPTI1MCwgZXhhZ2dlcmF0aW9uPTEwLCBtb21lbnR1bT0wLjYpCmVtYmVkX2QyID0gZW1iZWRfZDEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYWZmaW5fZHVjdC5zZXRfcGVycGxleGl0eSgzMCkKZW1iZWRfZDMgPSBlbWJlZF9kMi5vcHRpbWl6ZShuX2l0ZXI9NjAsIGV4YWdnZXJhdGlvbj0yLCBtb21lbnR1bT0wLjgpCmVtYmVkX2Q0ID0gZW1iZWRfZDMub3B0aW1pemUobl9pdGVyPTUwMCkKYGBgCgpXZSBwdWxsIHRoZSByZXN1bHRzIGludG8gUiwgbWFraW5nIHN1cmUgdG8gc2F2ZSB0aGUgQmFybmVzLUh1dCB0LVNORSByZXN1bHRzIGluIGFub3RoZXIgcmVkdWN0aW9uIHNsb3QuCgpgYGB7cn0KZW1iZWRfZHVjdCA8LSBhcy5tYXRyaXgocHkkZW1iZWRfZDQpCnJvd25hbWVzKGVtYmVkX2R1Y3QpIDwtIGNvbG5hbWVzKGR1Y3RhbCkKZHVjdGFsQHJlZHVjdGlvbnMkYmhfdHNuZSA8LSBkdWN0YWxAcmVkdWN0aW9ucyR0c25lCmR1Y3RhbEByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZHVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPSAiRml0U05FXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwNjQgPC0gRGltUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnA2NApgYGAKCiMjIyBDZWxsIFR5cGUgSWRlbnRpZmljYXRpb24gCgojIyMjIExpcGlkIFByb2Nlc3NpbmcKCldlIHVzZSBBTlBFUCBleHByZXNzaW9uIHRvIGlkZW50aWZ5IHRoZSBsaXBpZCBwcm9jZXNzaW5nIGR1Y3RhbCBjZWxscyBpbiBjbHVzdGVyIDcuIAoKYGBge3J9CnA2NSA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQU5QRVAiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNjUgLyBwNjQKYGBgCgojIyMjIFNlY3JldG9yeQoKRXhwcmVzc2lvbiBvZiBTT0QzIGFuZCBDRlRSIHJldmVhbHMgdGhlIHNlY3JldG9yeSBjZWxscyBpbiBjbHVzdGVyIDEuCgpgYGB7cn0KcDY2IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTT0QzIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDY3IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRlRSIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA2NiB8IHA2NykgLyBwNjQKYGBgCgojIyMjIENsYXNzaWNhbCAxCgpXZSB1c2UgVEZGMSBhbmQgVEZGMiBleHByZXNzaW9uIHRvIGFubm90YXRlIHRoZSBjbGFzc2ljYWwgMSBlcGl0aGVsaWFsIGNlbGxzIGluIGNsdXN0ZXJzIDAgYW5kIDUuIFdlIGNhbiBhbHNvIHNlZSB0aGF0IHRoZSB0d28gY2xhc3NpY2FsIDEgY2x1c3RlcnMgYXJlIHNwbGl0IGJ5IHRoZSBzYW1wbGUgZnJvbSB3aGljaCB0aGUgY2VsbHMgb3JpZ2luYXRlLiBHb2luZyBmb3J3YXJkLCB3ZSdsbCBzaW1wbHkgbGFiZWwgYm90aCBjbHVzdGVycyBhcyBjbGFzc2ljYWwgMS4gCgpgYGB7cn0KcDY4IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJURkYxIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDY5IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJURkYyIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDcwIDwtIERpbVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gInNhbXBsZSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTYW1wbGUiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNjggfCBwNzAgfCBwNjkpIC8gcDY0CmBgYAoKIyMjIyBDbGFzc2ljYWwgMgoKVGhlIGNsYXNzaWNhbCAyIGNlbGxzIGFyZSBsb2NhdGVkIGluIGNsdXN0ZXIgNiwgYXMgZXZpZGVuY2VkIGJ5IHRoZWlyIGV4cHJlc3Npb24gb2YgQ1JJU1AzLiAKCmBgYHtyfQpwNzEgPC0gRmVhdHVyZVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNSSVNQMyIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA3MSAvIHA2NApgYGAKCiMjIyMgQmFzYWwtbGlrZQoKVGhlIGJhc2FsIGNvbXBhcnRtZW50IHdlaWdodHMgZnJvbSBgREVDT0RFUmAgYXJlIGhpZ2hlc3QgaW4gY2x1c3RlciAzLCB3aGljaCB3ZSB3aWxsIGRlbm90ZSBhcyBiZWluZyBjb21wb3NlZCBvZiBiYXNhbC1saWtlIFBEQUMuIAoKYGBge3J9CnA3MiA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiYmFzYWwiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQmFzYWwtbGlrZSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDcyIC8gcDY0CmBgYAoKIyMjIyBDRDE2KyBNb25vY3l0ZQoKQXMgc2VlbiBlYXJsaWVyIGluIHRoZSByZXN1bHRzIG9mIHRoZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB0ZXh0LCB0aGUgdG9wIHRocmVlIGdlbmVzIGZvciBjbHVzdGVyIDIgd2VyZSBITEEtRFJBLCBITEEtRFBBMSwgYW5kIEhMQS1EUEIxLiBUaGlzIHBvaW50cyB0byBjbHVzdGVyIDIgYmVpbmcgc29tZSBraW5kIG9mIG15ZWxvaWQgY2VsbC4gV2UgdXNlIGV4cHJlc3Npb24gb2YgQ0QxNCwgQ0QxNiBha2EgRkNHUjNBLCBhbmQgTVM0QTcgdG8gaWRlbnRpZnkgaXQgYXMgY29udGFpbmluZyBDRDE0KyBDRDE2KyBtb25vY3l0ZXMuIAoKYGBge3J9CnA3MyA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QxNCIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA3NCA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiRkNHUjNBIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDc1IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJNUzRBNyIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNzMgfCBwNzQgfCBwNzUpIC8gcDY0CmBgYAoKQWxsIHRocmVlIGdlbmVzIGFyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBpbiBjbHVzdGVyIDIuIAoKYGBge3J9CmNsdXN0Ml9tYXJrZXJzIDwtIEZpbmRNYXJrZXJzKGR1Y3RhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkZW50LjEgPSAyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUpCmNsdXN0Ml9tYXJrZXJzICU+JSAKICBmaWx0ZXIocm93bmFtZXMoY2x1c3QyX21hcmtlcnMpICVpbiUgYygiQ0QxNCIsICJNUzRBNyIsICJGQ0dSM0EiKSkgJT4lIAogIGFycmFuZ2UoZGVzYygxIC0gcF92YWxfYWRqKSkKYGBgCgojIyMjIEFjaW5hcgoKTGFzdGx5LCB3ZSBzaG93IHRoYXQgY2x1c3RlciA0IGlzIGNvbXBvc2VkIG9mIGFjaW5hciBjZWxscyB1c2luZyBDVFJCMi4KCmBgYHtyfQpwNzYgPC0gRmVhdHVyZVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNUUkIyIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDc2IC8gcDY0CmBgYAoKIyMjIFZpc3VhbGl6YXRpb24KCldlIGFkZCBmaW5hbCBjbHVzdGVyIGxhYmVscyB0byBvdXIgYFNldXJhdGAgb2JqZWN0IGFuZCB2aXN1YWxpemUgdGhlIHJlc3VsdHMuCgpgYGB7cn0KZHVjdGFsJGxhYmVsIDwtIGNhc2Vfd2hlbihkdWN0YWwkc2V1cmF0X2NsdXN0ZXJzID09IDAgfiAiQ2xhc3NpY2FsIDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkdWN0YWwkc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiU2VjcmV0b3J5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSAyIH4gIkNEMTYrIE1vbm9jeXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSAzIH4gIkJhc2FsLWxpa2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkdWN0YWwkc2V1cmF0X2NsdXN0ZXJzID09IDQgfiAiQWNpbmFyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA1IH4gIkNsYXNzaWNhbCAxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA2IH4gIkNsYXNzaWNhbCAyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA3IH4gIkxpcGlkIHByb2MuIikKcDc3IDwtIERpbVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gImxhYmVsIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwNzcKYGBgCgojIyBQbGFzbWEgQ2VsbHMgJiBQbGFzbWFjeXRvaWQgRENzCgpXZSdsbCBydW4gYFNDSVNTT1JTYCBvbiBjbHVzdGVyIDExIGluIG9yZGVyIHRvIHJldmVhbCBpdHMgc3ViZ3JvdXBzLCB0aGUgcGxhc21hIGNlbGxzIGFuZCBwbGFzbWFjeXRvaWQgRENzLCBhcyBkZWZpbmVkIGJ5IHRoZWlyIGV4cHJlc3Npb24gb2YgSUdKIChha2EgSkNIQUlOKSBhbmQgSVJGNywgcmVzcGVjdGl2ZWx5LiAKCmBgYHtyfQpwNzggPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJKQ0hBSU4iKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiSkNIQUlOIC8gSUdKIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNzkgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJJUkY3IikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIklSRjciKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNzggfCBwNzkpIC8gcDQKYGBgCgojIyMgUmVjbHVzdGVyaW5nCgpXZSBydW4gYFNDSVNTT1JTYCB3aXRoIGRlZmF1bHQgcGFyYW1ldGVycy4gCgpgYGB7cn0KcGxhcyA8LSBSZWNsdXN0ZXJDZWxscyhwZGFjLCAKICAgICAgICAgICAgICAgICAgICAgICB3aGljaC5jbHVzdCA9IDExLCAKICAgICAgICAgICAgICAgICAgICAgICBuLlBDID0gMjAsIAogICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmRpbS5yZWR1YyA9ICJ0c25lIiwKICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgIGRvLnBsb3QgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpCnBsYXNfcGMgPC0gRW1iZWRkaW5ncyhwbGFzLCByZWR1Y3Rpb24gPSAicGNhIikKYGBgCgpFdmVuIHRob3VnaCBpbiB0aGlzIGNhc2UgaXQncyBwcm9iYWJseSBub3QgbmVjZXNzYXJ5LCB3ZSdsbCBydW4gRml0LVNORSBvbiB0aGUgY2VsbHMganVzdCBzbyB0aGF0IG91ciBheGlzIGxhYmVscyBhcmUgY29uc2lzdGVudC4gCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCnBsYXNfcGMgPSByLnBsYXNfcGMKIyBydW4gRml0LVNORQphZmZpbl9wbGFzID0gUGVycGxleGl0eUJhc2VkTk4ocGxhc19wYywgcGVycGxleGl0eT0zMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKHBsYXNfcGMsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmVfcGxhcyA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fcGxhcywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9wMSA9IHRzbmVfcGxhcy5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249MTIsIG1vbWVudHVtPTAuNikKZW1iZWRfcDIgPSBlbWJlZF9wMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQpgYGAKCmBgYHtyfQplbWJlZF9wbGFzIDwtIGFzLm1hdHJpeChweSRlbWJlZF9wMikKcm93bmFtZXMoZW1iZWRfcGxhcykgPC0gY29sbmFtZXMocGxhcykKcGxhc0ByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gcGxhc0ByZWR1Y3Rpb25zJHRzbmUKcGxhc0ByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfcGxhcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwODAgPC0gRGltUGxvdChwbGFzLCByZWR1Y3Rpb24gPSAidHNuZSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwODAKYGBgCgojIyMgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uCgpXZSB1c2UgdGhlIGFmb3JlbWVudGlvbmVkIG1hcmtlcnMgdG8gaWRlbnRpZnkgb3VyIHR3byBjbHVzdGVycy4gCgpgYGB7cn0KcDgxIDwtIEZlYXR1cmVQbG90KHBsYXMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSkNIQUlOIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkpDSEFJTiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDgyIDwtIEZlYXR1cmVQbG90KHBsYXMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSVJGNyIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJJUkY3IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDgxIHwgcDgyKSAvIHA4MApgYGAKCiMjIyBWaXN1YWxpemF0aW9uCgpBcyBiZWZvcmUsIHdlIGFkZCBjZWxsIGxhYmVscyBhbmQgdmlzdWFsaXplIHRoZSByZXN1bHRzLiAKCmBgYHtyfQpwbGFzJGxhYmVsIDwtIGNhc2Vfd2hlbihwbGFzJHNldXJhdF9jbHVzdGVycyA9PSAwIH4gIlBsYXNtYSIsIAogICAgICAgICAgICAgICAgICAgICAgICBwbGFzJHNldXJhdF9jbHVzdGVycyA9PSAxIH4gInBEQyIpCnA4MyA8LSBEaW1QbG90KHBsYXMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAibGFiZWwiKSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnA4MwpgYGAKCiMjIEIgQ2VsbHMKCldlIGNhbiBpZGVudGlmeSB0aGUgQiBjZWxscyBpbiBjbHVzdGVyIDQgdXNpbmcgam9pbnQgZXhwcmVzc2lvbiBvZiBNUzRBMSBhbmQgQ0Q3OUEuIFRoZSBjbHVzdGVyIGlzIHNwbGl0IGludG8gdHdvIHN1YmNsdXN0ZXJzIGJ5IHRpc3N1ZSB0eXBlOiBhZGphY2VudCBub3JtYWwgYW5kIFBEQUMuIFdoaWxlIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIGRldGVybWluZSB0aGUgZ2VuZXRpYyBkcml2ZXJzIG9mIHRoYXQgc2VwYXJhdGlvbiwgaXQncyBzb21ld2hhdCBvdXRzaWRlIG9mIG91ciBzY29wZSBoZXJlLiAKCmBgYHtyfQpwODQgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJNUzRBMSIpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIk1TNEExIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwODUgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDc5QSIpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkNENzlBIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwODYgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gImNvbmRpdGlvbiIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJUaXNzdWUgVHlwZSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA4NCB8IHA4NiB8IHA4NSkgLyBwNApgYGAKCiMjIE15ZWxvaWQgQ2VsbHMKCkxhc3RseSwgd2UnbGwgc3BsaXQgdXAgdGhlIG15ZWxvaWQgcG9wdWxhdGlvbiBieSB0aXNzdWUgY29uZGl0aW9uIChQREFDIHZzLiBhZGphY2VudCBub3JtYWwpIGp1c3QgbGlrZSB3ZSBkaWQgd2l0aCB0aGUgTksgLyBUIGNlbGxzLiBXZSdsbCBydW4gYFNDSVNTT1JTYCwgYW5ub3RhdGUgdGhlIGNsdXN0ZXJzLCBhbmQgdmlzdWFsaXplIHRoZSByZXN1bHRzLiAKCiMjIyBUdW1vciAKCkZpcnN0IHdlJ2xsIGF0dGVtcHQgdG8gYXNzaWduIGJyb2FkIGNlbGwgdHlwZSBsYWJlbHMgdG8gZWFjaCBvZiB0aGUgZm91ciBwdXRhdGl2ZSBteWVsb2lkIGNsdXN0ZXJzLiBXZSdsbCB1c2UgdGhlIG1hcmtlciBnZW5lcyBmcm9tIEVseWFkYSAqZXQgYWwqIG9uY2UgYWdhaW4uIAoKYGBge3J9Cm15b190dW1vciA8LSBzdWJzZXQocGRhYywgc3Vic2V0ID0gc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygxLCAyLCA2LCA5KSAmIGNvbmRpdGlvbiA9PSAiUERBQyIpCnA4NyA8LSBEaW1QbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiKSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnA4NwpgYGAKCkNsdXN0ZXIgMSBhcHBlYXJzIHRvIGJlIGNvbXBvc2VkIG9mIG91ciByZXNpZGVudCBtYWNyb3BoYWdlcyBkdWUgdG8gaXRzIGV4cHJlc3Npb24gb2YgQ0QxNCBhbmQgQzFRQS4gCgpgYGB7cn0KcDg4IDwtIEZlYXR1cmVQbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDE0IikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkNEMTQiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA4OSA8LSBGZWF0dXJlUGxvdChteW9fdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQzFRQSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDMVFBIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDg4IHwgcDg5KSAvIHA4NwpgYGAKCldlIGNhbiB1c2UgTFlaIGFuZCBTMTAwQTggZXhwcmVzc2lvbiB0byByZXZlYWwgdGhlIGNsYXNzaWMgbW9ub2N5dGVzIGFuZCBuZXV0cm9waGlscyBpbiBjbHVzdGVyIDIuIAoKYGBge3J9CnA5MCA8LSBGZWF0dXJlUGxvdChteW9fdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTFlaIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkxZWiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDkxIDwtIEZlYXR1cmVQbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTMTAwQTgiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiUzEwMEE4IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDkwIHwgcDkxKSAvIHA4NwpgYGAKCkNsdXN0ZXIgOSBzZWVtcyB0byBob3VzZSB0aGUgYWx0ZXJuYXRpdmVseSBhY3RpdmF0ZWQgbWFjcm9waGFnZXMsIGFzIHNob3duIGJ5IGV4cHJlc3Npb24gb2YgU1BQMS4gCgpgYGB7cn0KcDkyIDwtIEZlYXR1cmVQbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTUFAxIikgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlNQUDEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA5MiAvIHA4NwpgYGAKCkxhc3RseSwgd2Ugc2hvdyB0aGF0IGNsdXN0ZXIgNiBjb250YWlucyBvdXIgdmFyaW91cyBEQyBzdWJ0eXBlcyB0aHJvdWdoIGl0cyBleHByZXNzaW9uIG9mIEZDRVIxQSwgYSBjYW5vbmljYWwgZGVuZHJpdGljIGNlbGwgbWFya2VyLiAKCmBgYHtyfQpwOTMgPC0gRmVhdHVyZVBsb3QobXlvX3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkZDRVIxQSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJGQ0VSMUEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA5MyAvIHA4NwpgYGAKCiMjIyMgUmVjbHVzdGVyaW5nCgpTaW5jZSB3ZSd2ZSBhbHJlYWR5IGFubm90YXRlZCBzb21lIG9mIHRoZSBteWVsb2lkIGNlbGwgdHlwZXMsIHdlJ2xsIGZvY3VzIG9uIGNsdXN0ZXIgMiwgd2hpY2ggY29udGFpbnMgYm90aCBtb25vY3l0ZXMgYW5kIG5ldXRyb3BoaWxzLCBhbmQgdGhlIGRlbmRyaXRpYyBjZWxscyBpbiBjbHVzdGVyIDYuIAoKYGBge3J9Cm15b19yZWNsdXN0IDwtIFJlY2x1c3RlckNlbGxzKG15b190dW1vciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gYygyLCA2KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAxMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlLmNsdXN0ZXJzID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDEwLCAyMCwgMzAsIDQwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjIsIC4zLCAuNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnZhcmlhYmxlLmdlbmVzID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmRpbS5yZWR1YyA9ICJ0c25lIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZG8uZW1iZWRkaW5nID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvLnBsb3QgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQptb25vX3R1bW9yIDwtIG15b19yZWNsdXN0W1sxXV0KZGNfdHVtb3IgPC0gbXlvX3JlY2x1c3RbWzJdXQpgYGAKCldlJ2xsIGFnYWluIHJ1biBGaXQtU05FIG9uIG91ciByZWNsdXN0ZXJlZCBjZWxscy4gCgpgYGB7cn0KbW9ub190dW1vcl9wYyA8LSBFbWJlZGRpbmdzKG1vbm9fdHVtb3IsICJwY2EiKQpkY190dW1vcl9wYyA8LSBFbWJlZGRpbmdzKGRjX3R1bW9yLCAicGNhIikKYGBgCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCm1vbm9fcGMgPSByLm1vbm9fdHVtb3JfcGMKZGNfcGMgPSByLmRjX3R1bW9yX3BjCiMgRml0LVNORSAtIG1vbm9jeXRlcwphZmZpbl9tb25vID0gUGVycGxleGl0eUJhc2VkTk4obW9ub19wYywgcGVycGxleGl0eT0zMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKG1vbm9fcGMsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmVfbW9ubyA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fbW9ubywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9tb25vMSA9IHRzbmVfbW9uby5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249MTAsIG1vbWVudHVtPTAuNikKZW1iZWRfbW9ubzIgPSBlbWJlZF9tb25vMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQojIEZpdC1TTkUgLSBEQwphZmZpbl9kYyA9IFBlcnBsZXhpdHlCYXNlZE5OKGRjX3BjLCBwZXJwbGV4aXR5PTYwLCBtZXRyaWM9J2Nvc2luZScsIHJhbmRvbV9zdGF0ZT02MjkpCmluaXQgPSBpbml0aWFsaXphdGlvbi5wY2EoZGNfcGMsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmVfZGMgPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluX2RjLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkX2RjMSA9IHRzbmVfZGMub3B0aW1pemUobl9pdGVyPTI1MCwgZXhhZ2dlcmF0aW9uPTgsIG1vbWVudHVtPTAuNikKZW1iZWRfZGMyID0gZW1iZWRfZGMxLm9wdGltaXplKG5faXRlcj03NTAsIGV4YWdnZXJhdGlvbj0xLCBtb21lbnR1bT0wLjgpCmFmZmluX2RjLnNldF9wZXJwbGV4aXR5KDIwKQplbWJlZF9kYzMgPSBlbWJlZF9kYzIub3B0aW1pemUobl9pdGVyPTEwMCkKYGBgCgpXZSBwdWxsIHRoZSByZXN1bHRzIGJhY2sgaW50byBSIGFuZCB2aXN1YWxpemUgdGhlbS4gCgpgYGB7cn0KZW1iZWRfbW9ubyA8LSBhcy5tYXRyaXgocHkkZW1iZWRfbW9ubzIpCnJvd25hbWVzKGVtYmVkX21vbm8pIDwtIGNvbG5hbWVzKG1vbm9fdHVtb3IpCm1vbm9fdHVtb3JAcmVkdWN0aW9ucyRiaF90c25lIDwtIG1vbm9fdHVtb3JAcmVkdWN0aW9ucyR0c25lCm1vbm9fdHVtb3JAcmVkdWN0aW9ucyR0c25lPC0gQ3JlYXRlRGltUmVkdWNPYmplY3QoZW1iZWRkaW5ncyA9IGVtYmVkX21vbm8sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwOTQgPC0gRGltUGxvdChtb25vX3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkKcDk0CmBgYAoKYGBge3J9CmVtYmVkX2RjIDwtIGFzLm1hdHJpeChweSRlbWJlZF9kYzMpCnJvd25hbWVzKGVtYmVkX2RjKSA8LSBjb2xuYW1lcyhkY190dW1vcikKZGNfdHVtb3JAcmVkdWN0aW9ucyRiaF90c25lIDwtIGRjX3R1bW9yQHJlZHVjdGlvbnMkdHNuZQpkY190dW1vckByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZGMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPSAiRml0U05FXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwOTUgPC0gRGltUGxvdChkY190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiKSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnA5NQpgYGAKCiMjIyMgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uCgojIyMjIyBNb25vY3R5ZXMgJiBOZXV0cm9waGlscwoKRmlyc3Qgd2UgSUQgdGhlIG5ldXRyb3BoaWxzIGluIGNsdXN0ZXIgMSB1c2luZyBTMTAwQTggYW5kIFMxMDBBOSAtIG1hcmtlciBnZW5lcyB1c2VkIGJ5IEVseWFkYSAqZXQgYWwqLiAKCmBgYHtyfQpwOTYgPC0gRmVhdHVyZVBsb3QobW9ub190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTMTAwQTgiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiUzEwMEE4IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwOTcgPC0gRmVhdHVyZVBsb3QobW9ub190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTMTAwQTkiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiUzEwMEE5IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDk2IHwgcDk3KSAvIHA5NApgYGAKCldlIGNhbiBpZGVudGlmeSB0aGUgY2xhc3NpY2FsIG1vbm9jeXRlcyBpbiBjbHVzdGVyIDAgdGhyb3VnaCBleHByZXNzaW9uIG9mLCB5b3UgZ3Vlc3NlZCBpdCwgQ0QxNCwgYXMgd2VsbCBhcyBleHByZXNzaW9uIG9mIENEMTYgYWthIEZDR1IzQS4gCgpgYGB7cn0KcDk4IDwtIEZlYXR1cmVQbG90KG1vbm9fdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QxNCIpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDRDE0IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwOTkgPC0gRmVhdHVyZVBsb3QobW9ub190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJGQ0dSM0EiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQ0QxNiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA5OCB8IHA5OSkgLyBwOTQKYGBgCgpXZSBhZGQgY2VsbCBsYWJlbHMgdG8gb3VyIGBTZXVyYXRgIG9iamVjdCwgdGhlbiB3ZSdyZSBvZmYgdG8gdGhlIERDcy4gCgpgYGB7cn0KbW9ub190dW1vciRsYWJlbCA8LSBjYXNlX3doZW4obW9ub190dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJDbGFzc2ljYWwgTW9ub2N5dGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9ub190dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJOZXV0cm9waGlsIikKYGBgCgojIyMjIyBEZW5kcml0aWMgQ2VsbHMKCldlIGNhbiB1c2UgQ0xFQzlBIHRvIGFubm90YXRlIHRoZSBjREMxIHBvcHVsYXRpb24gaW4gY2x1c3RlciAyLiAKCmBgYHtyfQpwMTAwIDwtIEZlYXR1cmVQbG90KGRjX3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNMRUM5QSIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkNMRUM5QSIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDEwMCAvIHA5NQpgYGAKCkpvaW50IGV4cHJlc3Npb24gb2YgQ0QxQSBhbmQgQ0QyMDcgcmV2ZWFscyB0aGUgTGFuZ2VyaGFucy1saWtlIERDcyBpbiBjbHVzdGVyIDAuIAoKYGBge3J9CnAxMDEgPC0gRmVhdHVyZVBsb3QoZGNfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QxQSIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkNEMUEiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMDIgPC0gRmVhdHVyZVBsb3QoZGNfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QyMDciKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDRDIwNyIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMDEgfCBwMTAyKSAvIHA5NQpgYGAKCk5leHQgd2UgdXNlIExBTVAzIHRvIGlkZW50aWZ5IHRoZSBhY3RpdmF0ZWQgRENzIGluIGNsdXN0ZXIgMy4gCgpgYGB7cn0KcDEwMyA8LSBGZWF0dXJlUGxvdChkY190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJMQU1QMyIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkxBTVAzIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTAzIC8gcDk1CmBgYAoKVXNpbmcgYSBXaWxjb3hvbiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB0ZXN0IHNob3dzIHRoYXQgY2x1c3RlciAxIGlzIGNoYXJhY3Rlcml6ZWQgYnkgW3NldmVyYWwgY29udmVudGlvbmwgREMyIG1hcmtlciBnZW5lcyAvIHRyYW5zY3JpcHRpb24gZmFjdG9yc10oaHR0cHM6Ly9vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvcGRmLzEwLjExMTEvaW1tLjEyODg4KS4gCgpgYGB7cn0KZGNfdHVtb3JfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhkY190dW1vciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gLjMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKZGNfdHVtb3JfbWFya2VycyAlPiUgCiAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSAmIGNsdXN0ZXIgPT0gMSAmIGdlbmUgJWluJSBjKCJDTEVDMTBBIiwgIktMRjQiLCAiWkVCMiIpKQpgYGAKCmBgYHtyfQpwMTA0IDwtIEZlYXR1cmVQbG90KGRjX3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNMRUMxMEEiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMDUgPC0gRmVhdHVyZVBsb3QoZGNfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiS0xGNCIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDEwNiA8LSBGZWF0dXJlUGxvdChkY190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJaRUIyIikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDEwNCB8IHAxMDUgfCBwMTA2KSAvIHA5NQpgYGAKCldlIGFkZCBmaW5hbCBzdWJjbHVzdGVyIGNlbGwgdHlwZSBsYWJlbHMgdG8gb3VyIGBTZXVyYXRgIG9iamVjdCwgYW5kIHRoZW4gd2UncmUgb2ZmIHRvIHRoZSBtYWNyb3BoYWdlcy4gCgpgYGB7cn0KZGNfdHVtb3IkbGFiZWwgPC0gY2FzZV93aGVuKGRjX3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSAwIH4gIkxhbmdlcmhhbnMtbGlrZSBEQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGNfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiY0RDMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGNfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiY0RDMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGNfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDMgfiAiQWN0aXZhdGVkIERDIikKYGBgCgojIyMjIFZpc3VhbGl6YXRpb24KCiMjIyMjIE1vbm9jeXRlcyAmIE5ldXRyb3BoaWxzCgpgYGB7cn0KcDEwNyA8LSBEaW1QbG90KG1vbm9fdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAibGFiZWwiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkKcDEwNwpgYGAKCiMjIyMjIERDcwoKYGBge3J9CnAxMDggPC0gRGltUGxvdChkY190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJsYWJlbCIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwMTA4CmBgYAoKIyMjIEFkamFjZW50IE5vcm1hbAoKV2UgaGF2ZSB0aGUgc2FtZSBmb3VyIGNsdXN0ZXJzIGFzIGluIHRoZSB0dW1vciB0aXNzdWU6IDEsIDIsIDYsIGFuZCA5LiBXZSBrbm93IHRoYXQgY2x1c3RlcnMgMSBhbmQgOSBhcmUgY29tcG9zZWQgb2YgdGhlIHJlc2lkZW50IGFuZCBhbHRlcm5hdGl2ZWx5LWFjdGl2YXRlZCBtYWNyb3BoYWdlcywgcmVzcGVjdGl2ZWx5LiBXZSdsbCBmb2N1cyBvbiB0aGUgbW9ub2N5dGVzICYgbmV1dHJvcGhpbHMgYW5kIERDcyBpbiBjbHVzdGVycyAyIGFuZCA2LCByZXNwZWN0aXZlbHkuIAoKYGBge3J9Cm15b19ub3JtIDwtIHN1YnNldChwZGFjLCBzdWJzZXQgPSBzZXVyYXRfY2x1c3RlcnMgJWluJSBjKDEsIDIsIDYsIDkpICYgY29uZGl0aW9uID09ICJBZGpOb3JtIikKYGBgCgojIyMjIFJlY2x1c3RlcmluZwoKYGBge3J9Cm15b19ub3JtX3JlY2x1c3QgPC0gUmVjbHVzdGVyQ2VsbHMobXlvX25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gYygyLCA2KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVyZ2UuY2x1c3RlcnMgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi52YXJpYWJsZS5nZW5lcyA9IDQwMDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAxMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guZGltLnJlZHVjID0gInRzbmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQptb25vX25vcm0gPC0gbXlvX25vcm1fcmVjbHVzdFtbMV1dCmRjX25vcm0gPC0gbXlvX25vcm1fcmVjbHVzdFtbMl1dCmBgYAoKRm9yIHRoZSBsYXN0IHRpbWUsIHdlIHJ1biBGaXQtU05FIGluIG9yZGVyIHRvIG9idGFpbiBhIGJldHRlciBlbWJlZGRpbmcuIAoKYGBge3J9Cm1vbm9fbm9ybV9wYyA8LSBFbWJlZGRpbmdzKG1vbm9fbm9ybSwgInBjYSIpCmRjX25vcm1fcGMgPC0gRW1iZWRkaW5ncyhkY19ub3JtLCAicGNhIikKYGBgCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCm1vbm9fcGMgPSByLm1vbm9fbm9ybV9wYwpkY19wYyA9IHIuZGNfbm9ybV9wYwojIEZpdC1TTkUgLSBtb25vY3l0ZXMKYWZmaW5fbW9ubyA9IFBlcnBsZXhpdHlCYXNlZE5OKG1vbm9fcGMsIHBlcnBsZXhpdHk9MzAsIG1ldHJpYz0nY29zaW5lJywgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShtb25vX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX21vbm8gPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluX21vbm8sIG5lZ2F0aXZlX2dyYWRpZW50X21ldGhvZD0nZmZ0JykKZW1iZWRfbW9ubzEgPSB0c25lX21vbm8ub3B0aW1pemUobl9pdGVyPTI1MCwgZXhhZ2dlcmF0aW9uPTEwLCBtb21lbnR1bT0wLjYpCmVtYmVkX21vbm8yID0gZW1iZWRfbW9ubzEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKIyBGaXQtU05FIC0gREMKYWZmaW5fZGMgPSBQZXJwbGV4aXR5QmFzZWROTihkY19wYywgcGVycGxleGl0eT0zMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKGRjX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX2RjID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9kYywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9kYzEgPSB0c25lX2RjLm9wdGltaXplKG5faXRlcj0yNTAsIGV4YWdnZXJhdGlvbj04LCBtb21lbnR1bT0wLjYpCmVtYmVkX2RjMiA9IGVtYmVkX2RjMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQpgYGAKCldlIHB1bGwgdGhlIHJlc3VsdHMgYmFjayBpbnRvIFIgYW5kIHZpc3VhbGl6ZSB0aGVtLiAKCmBgYHtyfQplbWJlZF9tb25vIDwtIGFzLm1hdHJpeChweSRlbWJlZF9tb25vMikKcm93bmFtZXMoZW1iZWRfbW9ubykgPC0gY29sbmFtZXMobW9ub19ub3JtKQptb25vX25vcm1AcmVkdWN0aW9ucyRiaF90c25lIDwtIG1vbm9fbm9ybUByZWR1Y3Rpb25zJHRzbmUKbW9ub19ub3JtQHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9tb25vLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDEwOSA8LSBEaW1QbG90KG1vbm9fbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkKcDEwOQpgYGAKCmBgYHtyfQplbWJlZF9kYyA8LSBhcy5tYXRyaXgocHkkZW1iZWRfZGMyKQpyb3duYW1lcyhlbWJlZF9kYykgPC0gY29sbmFtZXMoZGNfbm9ybSkKZGNfbm9ybUByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gZGNfbm9ybUByZWR1Y3Rpb25zJHRzbmUKZGNfbm9ybUByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZGMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwMTEwIDwtIERpbVBsb3QoZGNfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkKcDExMApgYGAKCiMjIyMgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uCgojIyMjIyBNb25vY3l0ZXMgJiBOZXV0cm9waGlscwoKV2UgdXNlIGhpZ2ggUzEwMEE4IGFuZCBTMTAwQTkgZXhwcmVzc2lvbiB0byBkZWZpbmUgdGhlIG5ldXRyb3BoaWxzIGluIGNsdXN0ZXIgMi4gCgpgYGB7cn0KcDExMSA8LSBGZWF0dXJlUGxvdChtb25vX25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUzEwMEE4IikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTEyIDwtIEZlYXR1cmVQbG90KG1vbm9fbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTMTAwQTkiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMTExIHwgcDExMikgLyBwMTA5CmBgYAoKTmV4dCB1cCBhcmUgdGhlIGNsYXNzaWNhbCBtb25vY3l0ZXMgaW4gY2x1c3RlcnMgMCBhbmQgMSwgc3BsaXQgYnkgc2FtcGxlLiAKCmBgYHtyfQpwMTEzIDwtIEZlYXR1cmVQbG90KG1vbm9fbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDY4IikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTE0IDwtIEZlYXR1cmVQbG90KG1vbm9fbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDE0IikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTE1IDwtIERpbVBsb3QobW9ub19ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gInNhbXBsZSIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlNhbXBsZSIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMTMgfCBwMTE1IHwgcDExNCkgLyBwMTA5CmBgYAoKTGFzdGx5LCBpdCBzZWVtcyB3ZSBoYXZlIGEgc21hbGwgZ3JvdXAgb2YgQ0Q4KyBUIGNlbGxzIGluIGNsdXN0ZXIgMyB0aGF0IHNudWNrIGludG8gdGhlIG15ZWxvaWQgY2x1c3RlciwgYXMgZGVmaW5lZCBieSB0aGVpciBleHByZXNzaW9uIG9mIENEMiwgQ0QzRCAobWFya2luZyB0aGVtIGFzIE5LIC8gVCBjZWxscyksIGFuZCBDRDhBICYgTktHNy4gSSBkb24ndCBiZWxpZXZlIHRoZXkncmUgTksgY2VsbHMgYXMgdGhlIGRvIG5vdCBleHByZXNzIFBSRjEgb3IgR1pNQi4gCgpgYGB7cn0KcDExNiA8LSBGZWF0dXJlUGxvdChtb25vX25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QyIikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTE3IDwtIEZlYXR1cmVQbG90KG1vbm9fbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDNEIikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTE4IDwtIEZlYXR1cmVQbG90KG1vbm9fbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDhBIikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTE5IDwtIEZlYXR1cmVQbG90KG1vbm9fbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJOS0c3IikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQooKHAxMTYgfCBwMTE3KSAvIChwMTE4IHwgcDExOSkpIC8gcDEwOQpgYGAKCldlIGFkZCBsYWJlbHMgdG8gb3VyIGNsdXN0ZXJzLiAKCmBgYHtyfQptb25vX25vcm0kbGFiZWwgPC0gY2FzZV93aGVuKG1vbm9fbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJDbGFzc2ljIE1vbm9jeXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9ub19ub3JtJHNldXJhdF9jbHVzdGVycyA9PSAxIH4gIkNsYXNzaWMgTW9ub2N5dGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb25vX25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiTmV1dHJvcGhpbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vbm9fbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMyB+ICJDRDgrIFQiKQpgYGAKCiMjIyMjIERlbmRyaXRpYyBDZWxscwoKV2UgYW5ub3RhdGUgY2x1c3RlciAxIGFzIGNvbnZlbnRpb25hbCBEQzEgYW5kIGNsdXN0ZXIgMCBhcyBjb252ZW50aW9uYWwgREMyIHRocm91Z2ggbXV0dWFsbHkgZXhjbHVzaXZlIGV4cHJlc3Npb24gb2YgdGhlIGNhbm9uaWNhbCBtYXJrZXJzIENMRUM5QSBhbmQgQ0xFQzEwQSwgcmVzcGVjdGl2ZWx5LiAKCmBgYHtyfQpwMTIwIDwtIEZlYXR1cmVQbG90KGRjX25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0xFQzlBIikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTIxIDwtIEZlYXR1cmVQbG90KGRjX25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0xFQzEwQSIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMjAgfCBwMTIxKSAvIHAxMTAKYGBgCgpMYWJlbHMgYXJlIGFkZGVkIHRvIG91ciBhZGphY2VudCBub3JtYWwgdGlzc3VlIERDIGBTZXVyYXRgIG9iamVjdC4gCgpgYGB7cn0KZGNfbm9ybSRsYWJlbCA8LSBjYXNlX3doZW4oZGNfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJjREMyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRjX25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiY0RDMSIpCmBgYAoKIyMjIyBWaXN1YWxpemF0aW9uCgpIZXJlIGFyZSB0aGUgZmluYWwgYW5ub3RhdGlvbnMgZm9yIHRoZSBhZGphY2VudCBub3JtYWwgdGlzc3VlIG15ZWxvaWQgcG9wdWxhdGlvbi4gCgpgYGB7cn0KcDEyMiA8LSBEaW1QbG90KG1vbm9fbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJsYWJlbCIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJhd3Rvb2xzOjptcGFsZXR0ZSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwMTIyCmBgYAoKYGBge3J9CnAxMjMgPC0gRGltUGxvdChkY19ub3JtLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gImxhYmVsIikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImF3dG9vbHM6Om1wYWxldHRlIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCnAxMjMKYGBgCgojIENvbmNsdXNpb25zCgojIFNhdmUgRmlndXJlcyAmIERhdGEKCldlJ2xsIGNyZWF0ZSBhIHF1aWNrIGNvbnZlbmllbmNlIGZ1bmN0aW9uIHRvIGhlbHAgdXMgc2F2ZSB0aGUgZmlndXJlcy4KCmBgYHtyfQpzYXZlU0NJU1NPUlMgPC0gZnVuY3Rpb24ocGxvdCA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwdWIucmVhZHkgPSBGQUxTRSkgewogIGlmIChpcy5udWxsKHBsb3QpIHwgaXMubnVsbChuYW1lKSkgc3RvcCgiWW91IGZvcmdvdCBzb21lIGFyZ3VtZW50cy4iKQogIGlmIChwdWIucmVhZHkpIHsKICAgIGRpciA8LSAifi9EZXNrdG9wL1IvU0NJU1NPUlMvdmlnbmV0dGVzL2ZpZ3VyZXNfcHViL0VseWFkYS8iCiAgICBpZiAoIWJvcmRlcikgewogICAgICBwbG90IDwtIHBsb3QgKyAKICAgICAgICAgICAgICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAgIH0gZWxzZSB7CiAgICAgIHBsb3QgPC0gcGxvdCArIAogICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAgIH0KICAgIGdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChuYW1lLCAiLnBkZiIpLCAKICAgICAgICAgICBkZXZpY2UgPSAicGRmIiwgCiAgICAgICAgICAgdW5pdHMgPSAiaW4iLAogICAgICAgICAgIHBhdGggPSBkaXIsIAogICAgICAgICAgIGhlaWdodCA9IDUsIAogICAgICAgICAgIHdpZHRoID0gNSkgCiAgfSBlbHNlIHsKICAgIGRpciA8LSAifi9EZXNrdG9wL1IvU0NJU1NPUlMvdmlnbmV0dGVzL2ZpZ3VyZXNfc3VwcC9FbHlhZGEvIgogICAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKG5hbWUsICIucGRmIiksIAogICAgICAgICAgIGRldmljZSA9ICJwZGYiLCAKICAgICAgICAgICB1bml0cyA9ICJpbiIsCiAgICAgICAgICAgcGF0aCA9IGRpciwgCiAgICAgICAgICAgaGVpZ2h0ID0gNSwgCiAgICAgICAgICAgd2lkdGggPSA1KSAKICB9Cn0KYGBgCgpUaGlzIHNlY3Rpb24gaXNuJ3Qgd29ydGggcmVhZGluZzsgaXQncyBoZXJlIHNvbGVseSB0byBwcm92ZSB0aGF0IHRoZSBmaWd1cmVzIHdlIHByZXNlbnQgaW4gb3VyIHB1YmxpY2F0aW9uIHdlcmUgZHluYW1pY2FsbHkgZ2VuZXJhdGVkIGR1cmluZyB0aGUga25pdHRpbmcgb2YgdGhpcyBkb2N1bWVudC4KCmBgYHtyfQpzYXZlU0NJU1NPUlMocGxvdCA9IHAwLCBuYW1lID0gIlNldXJhdF9DbHVzdGVyc190U05FLnBkZiIsIHB1Yi5yZWFkeSA9IFRSVUUsIGJvcmRlciA9IEZBTFNFKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAxLCBuYW1lID0gIlNldXJhdF9DbHVzdGVyc19VTUFQLnBkZiIsIHB1Yi5yZWFkeSA9IFRSVUUsIGJvcmRlciA9IEZBTFNFKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA0LCBuYW1lID0gIlNldXJhdF9DbHVzdGVyc19GaXRTTkUucGRmIiwgcHViLnJlYWR5ID0gVFJVRSwgYm9yZGVyID0gRkFMU0UpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDUsIG5hbWUgPSAiU2luZ2xlUl9Bbm5vc19zY19yZWYucGRmIiwgcHViLnJlYWR5ID0gVFJVRSwgYm9yZGVyID0gRkFMU0UpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDYsIG5hbWUgPSAiU2luZ2xlUl9Bbm5vc19idWxrX3JlZi5wZGYiLCBwdWIucmVhZHkgPSBUUlVFLCBib3JkZXIgPSBGQUxTRSkKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNywgbmFtZSA9ICJDT05JQ1NtYXRfQW5ub3MucGRmIiwgcHViLnJlYWR5ID0gVFJVRSwgYm9yZGVyID0gRkFMU0UpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDgsIG5hbWUgPSAiREVDT0RFUl9iYXNhbC5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA5LCBuYW1lID0gIkRFQ09ERVJfY2xhc3NpY2FsLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDEwLCBuYW1lID0gIkRFQ09ERVJfZXhvY3JpbmUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTEsIG5hbWUgPSAiREVDT0RFUl9lbmRvY3JpbmUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTIsIG5hbWUgPSAiREVDT0RFUl9pbW11bmUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTMsIG5hbWUgPSAiREVDT0RFUl9ub3JtYWxfc3Ryb21hLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDE0LCBuYW1lID0gIkRFQ09ERVJfYWN0X3N0cm9tYS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAxNSwgbmFtZSA9ICJGaWJyb19hbGxfY2VsbHNfQ09MMUExLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDE2LCBuYW1lID0gIkZpYnJvX2FsbF9jZWxsc19DT0wzQTEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTcsIG5hbWUgPSAiRmlicm9fYWxsX2NlbGxzX0xVTS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAxOCwgbmFtZSA9ICJGaWJyb19hbGxfY2VsbHNfRENOLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDE5LCBuYW1lID0gIkZpYnJvX1NDSVNTT1JTX0ZpdFNORS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAyMCwgbmFtZSA9ICJGaWJyb19pQ0FGX1ZBTS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAyMSwgbmFtZSA9ICJGaWJyb19teUNBRl9WQU0ucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMjIsIG5hbWUgPSAiRmlicm9fYXBDQUZfVkFNLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDIzLCBuYW1lID0gIkZpYnJvX2ZpbmFsX2xhYmVscy5wZGYiLCBwdWIucmVhZHkgPSBUUlVFLCBib3JkZXIgPSBGQUxTRSkKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMjQsIG5hbWUgPSAiRW5kb19QZXJpdmFzY3VsYXJfU0NJU1NPUlNfRml0U05FLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDI1LCBuYW1lID0gIlBlcml2YXNjdWxhcl9JR0ZCUDcucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMjYsIG5hbWUgPSAiUGVyaXZhc2N1bGFyX0FDVEEyLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDI3LCBuYW1lID0gIlBlcml2YXNjdWxhcl9SR1M1LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDI4LCBuYW1lID0gIkVuZG90aGVsaWFsX1BMVkFQLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDI5LCBuYW1lID0gIkVuZG90aGVsaWFsX1ZXRi5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAzMCwgbmFtZSA9ICJFbmRvX1Blcml2YXNjdWxhcl9maW5hbF9sYWJlbHMucGRmIiwgcHViLnJlYWR5ID0gVFJVRSwgYm9yZGVyID0gRkFMU0UpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDMxLCBuYW1lID0gIk5LVF9hbGxfY2VsbHNfQ0QzRC5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAzMiwgbmFtZSA9ICJOS1RfVHVtb3JfU0NJU1NPUlNfRml0U05FLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDMzLCBuYW1lID0gIk5LVF9UdW1vcl9DRDRUX0lMN1IucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMzQsIG5hbWUgPSAiTktUX1R1bW9yX0NENFRfQ0Q2OS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAzNSwgbmFtZSA9ICJOS1RfVHVtb3JfVHJlZ19JTDJSQS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAzNiwgbmFtZSA9ICJOS1RfVHVtb3JfVHJlZ19GT1hQMy5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAzNywgbmFtZSA9ICJOS1RfVHVtb3JfUHJvbGlmX1RyZWdfVE9QMkEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMzgsIG5hbWUgPSAiTktUX1R1bW9yX01hc3RfVFBTQUIxLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDM5LCBuYW1lID0gIk5LVF9UdW1vcl9OS19OS0c3LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDQwLCBuYW1lID0gIk5LVF9UdW1vcl9OS19QUkYxLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDQxLCBuYW1lID0gIk5LVF9UdW1vcl9DRDhUX0NEOEEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNDIsIG5hbWUgPSAiTktUX1R1bW9yX0NEOFRfQ0QyLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDQzLCBuYW1lID0gIk5LVF9UdW1vcl9JbnRlcm1lZGlhdGVfTW9ub19MWVoucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNDQsIG5hbWUgPSAiTktUX1R1bW9yX0ludGVybWVkaWF0ZV9Nb25vX0hMQURSQS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA0NSwgbmFtZSA9ICJOS1RfVHVtb3JfSW50ZXJtZWRpYXRlX01vbm9fQ0Q3NC5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA0NiwgbmFtZSA9ICJOS1RfVHVtb3JfSW50ZXJtZWRpYXRlX01vbm9fSExBRFBCMS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA0NywgbmFtZSA9ICJOS1RfVHVtb3JfZmluYWxfbGFiZWxzLnBkZiIsIHB1Yi5yZWFkeSA9IFRSVUUsIGJvcmRlciA9IEZBTFNFKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA0OCwgbmFtZSA9ICJOS1RfTm9ybV9TQ0lTU09SU19GaXRTTkUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNDksIG5hbWUgPSAiTktUX05vcm1fQ0Q0VF9JTDdSLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDUwLCBuYW1lID0gIk5LVF9Ob3JtX0NENFRfUzEwMEE0LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDUxLCBuYW1lID0gIk5LVF9Ob3JtX0NENFRfQ0NSNy5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA1MiwgbmFtZSA9ICJOS1RfTm9ybV9DRDhUX0NEOEEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNTMsIG5hbWUgPSAiTktUX05vcm1fVHJlZ19USUdJVC5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA1NCwgbmFtZSA9ICJOS1RfTm9ybV9UcmVnX0ZPWFAzLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDU1LCBuYW1lID0gIk5LVF9Ob3JtX05LX1BSRjEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNTYsIG5hbWUgPSAiTktUX05vcm1fTktfTktHNy5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA1NywgbmFtZSA9ICJOS1RfTm9ybV9Qcm9saWZfVHJlZ19UT1AyQS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA1OCwgbmFtZSA9ICJOS1RfTm9ybV9JbnRlcm1lZGlhdGVfTW9ub19MWVoucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNTksIG5hbWUgPSAiTktUX05vcm1fSW50ZXJtZWRpYXRlX01vbm9fSExBRFJBLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDYwLCBuYW1lID0gIk5LVF9Ob3JtX0ludGVybWVkaWF0ZV9Nb25vX0xTVDEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNjEsIG5hbWUgPSAiTktUX05vcm1fSW50ZXJtZWRpYXRlX01vbm9fVFlST0JQLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDYyLCBuYW1lID0gIk5LVF9Ob3JtX1NDSVNTT1JTX0ZpdFNORS5wZGYiLCBwdWIucmVhZHkgPSBUUlVFLCBib3JkZXIgPSBGQUxTRSkKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNjMsIG5hbWUgPSAiRHVjdGFsX2FsbF9jZWxsc19LUlQ4LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDY0LCBuYW1lID0gIkR1Y3RhbF9TQ0lTU09SU19GaXRTTkUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNjUsIG5hbWUgPSAiRHVjdGFsX0xpcGlkX1Byb2NfQU5QRVAucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNjYsIG5hbWUgPSAiRHVjdGFsX1NlY3JldG9yeV9TT0QzLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDY3LCBuYW1lID0gIkR1Y3RhbF9TZWNyZXRvcnlfQ0ZUUi5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA2OCwgbmFtZSA9ICJEdWN0YWxfQ2xhc3NpY2FsMV9URkYxLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDY5LCBuYW1lID0gIkR1Y3RhbF9DbGFzc2ljYWwxX1RGRjIucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNzAsIG5hbWUgPSAiRHVjdGFsX0NsYXNzaWNhbDFfU2FtcGxlSUQucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNzEsIG5hbWUgPSAiRHVjdGFsX0NsYXNzaWNhbDJfQ1JJU1AzLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDcyLCBuYW1lID0gIkR1Y3RhbF9iYXNhbF9ERUNPREVSLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDczLCBuYW1lID0gIkR1Y3RhbF9DRDE2X01vbm9fQ0QxNC5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA3NCwgbmFtZSA9ICJEdWN0YWxfQ0QxNl9Nb25vX0ZDR1IzQS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA3NSwgbmFtZSA9ICJEdWN0YWxfQ0QxNl9Nb25vX01TNEE3LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDc2LCBuYW1lID0gIkR1Y3RhbF9BY2luYXJfQ1RSQjIucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNzcsIG5hbWUgPSAiRHVjdGFsX2ZpbmFsX2xhYmVscy5wZGYiLCBwdWIucmVhZHkgPSBUUlVFLCBib3JkZXIgPSBGQUxTRSkKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNzgsIG5hbWUgPSAiUGxhc21hX2FsbF9jZWxsc19JR0oucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwNzksIG5hbWUgPSAiUGxhc21hX2FsbF9jZWxsc19JUkY3LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDgwLCBuYW1lID0gIlBsYXNtYV9TQ0lTU09SU19GaXRTTkUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwODEsIG5hbWUgPSAiUGxhc21hX1BsYXNtYV9KQ0hBSU4ucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwODIsIG5hbWUgPSAiUGxhc21hX3BEQ19JR0oucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwODMsIG5hbWUgPSAiUGxhc21hX2ZpbmFsX2xhYmVscy5wZGYiLCBwdWIucmVhZHkgPSBUUlVFLCBib3JkZXIgPSBGQUxTRSkKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwODQsIG5hbWUgPSAiQl9hbGxfY2VsbHNfTVM0QTEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwODUsIG5hbWUgPSAiQl9hbGxfY2VsbHNfQ0Q3OUEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwODYsIG5hbWUgPSAiQl9hbGxfY2VsbHNfdGlzc3VlX3R5cGUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwODcsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9vcmlnaW5hbF9GaXRTTkUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwODgsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9SZXNpZGVudF9NYWNyb19DRDE0LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDg5LCBuYW1lID0gIk15ZWxvaWRfVHVtb3JfUmVzaWRlbnRfTWFjcm9fQzFRQS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA5MCwgbmFtZSA9ICJNeWVsb2lkX1R1bW9yX0NsYXNzaWNfTW9ub19MWVoucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwOTEsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9DbGFzc2ljX01vbm9fUzEwMEE4LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDkyLCBuYW1lID0gIk15ZWxvaWRfVHVtb3JfQWx0ZXJuYXRpdmVfTWFjcm9fU3BwMS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA5MywgbmFtZSA9ICJNeWVsb2lkX1R1bW9yX0RDX0ZDRVIxQS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHA5NCwgbmFtZSA9ICJNb25vY3l0ZV9UdW1vcl9TQ0lTU09SU19GaXRTTkUucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwOTUsIG5hbWUgPSAiRENfVHVtb3JfU0NJU1NPUlNfRml0U05FLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDk2LCBuYW1lID0gIk1vbm9jeXRlX1R1bW9yX05ldXRyb3BoaWxfUzEwMEE4LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDk3LCBuYW1lID0gIk1vbm9jeXRlX1R1bW9yX05ldXRyb3BoaWxfUzEwMEE5LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDk4LCBuYW1lID0gIk1vbm9jeXRlX1R1bW9yX0NsYXNzaWNfTW9ub19DRDE0LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDk5LCBuYW1lID0gIk1vbm9jeXRlX1R1bW9yX0NsYXNzaWNfTW9ub19GQ0dSM0EucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTAwLCBuYW1lID0gIkRDX1R1bW9yX2NEQzFfQ0xFQzlBLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDEwMSwgbmFtZSA9ICJEQ19UdW1vcl9MYW5nZXJoYW5zX0RDX0NEMUEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTAyLCBuYW1lID0gIkRDX1R1bW9yX0xhbmdlcmhhbnNfRENfQ0QyMDcucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTAzLCBuYW1lID0gIkRDX1R1bW9yX0FjdGl2YXRlZF9EQ19MQU1QMy5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAxMDQsIG5hbWUgPSAiRENfVHVtb3JfY0RDMl9DTEVDMTBBLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDEwNSwgbmFtZSA9ICJEQ19UdW1vcl9jREMyX0tMRjQucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTA2LCBuYW1lID0gIkRDX1R1bW9yX2NEQzJfWkVCMi5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAxMDcsIG5hbWUgPSAiTW9ub19UdW1vcl9maW5hbF9sYWJlbHMucGRmIiwgcHViLnJlYWR5ID0gVFJVRSwgYm9yZGVyID0gRkFMU0UpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDEwOCwgbmFtZSA9ICJEQ19UdW1vcl9maW5hbF9sYWJlbHMucGRmIiwgcHViLnJlYWR5ID0gVFJVRSwgYm9yZGVyID0gRkFMU0UpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDEwOSwgbmFtZSA9ICJNb25vX05vcm1fU0NJU1NPUlNfRml0U05FLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDExMCwgbmFtZSA9ICJEQ19Ob3JtX1NDSVNTT1JTX0ZpdFNORS5wZGYiKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAxMTEsIG5hbWUgPSAiTW9ub19Ob3JtX05ldXRyb3BoaWxfUzEwMEE4LnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDExMiwgbmFtZSA9ICJNb25vX05vcm1fTmV1dHJvcGhpbF9TMTAwQTkucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTEzLCBuYW1lID0gIk1vbm9fTm9ybV9DbGFzc2ljX01vbm9jeXRlX0NENjgucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTE0LCBuYW1lID0gIk1vbm9fTm9ybV9DbGFzc2ljX01vbm9jeXRlX0NEMTQucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTE1LCBuYW1lID0gIk1vbm9fTm9ybV9DbGFzc2ljX01Pbm9jeXRlX1NhbXBsZUlELnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDExNiwgbmFtZSA9ICJNb25vX05vcm1fQ0Q4VF9DRDIucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTE3LCBuYW1lID0gIk1vbm9fTm9ybV9DRDhUX0NEM0QucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTE4LCBuYW1lID0gIk1vbm9fTm9ybV9DRDhUX0NEOEEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTE5LCBuYW1lID0gIk1vbm9fTm9ybV9DRDhUX05LRzcucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTIwLCBuYW1lID0gIkRDX05vcm1fY0RDMV9DTEVDOUEucGRmIikKc2F2ZVNDSVNTT1JTKHBsb3QgPSBwMTIxLCBuYW1lID0gIkRDX05vcm1fY0RDMl9DTEVDMTBBLnBkZiIpCnNhdmVTQ0lTU09SUyhwbG90ID0gcDEyMiwgbmFtZSA9ICJNb25vX05vcm1fZmluYWxfbGFiZWxzLnBkZiIsIHB1Yi5yZWFkeSA9IFRSVUUsIGJvcmRlciA9IEZBTFNFKQpzYXZlU0NJU1NPUlMocGxvdCA9IHAxMjMsIG5hbWUgPSAiRENfTm9ybV9maW5hbF9sYWJlbHMucGRmIiwgcHViLnJlYWR5ID0gVFJVRSwgYm9yZGVyID0gRkFMU0UpCmBgYAoKQW5kIG9mIGNvdXJzZToKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAo=